爬取需要登录信息的网站
不知道算不算违规,不过还是记录一下,属于比较有用的小技巧。有的网站需要登录,才能查看其里面的东西。有时候如果只是文字的东西,想要分享出去。比如说极客时间的专栏。
那就爬取内容保存下来吧。
方法
1 留意自己想要爬的内容,如果可以提前获取其内容链接,并且链接是固定的,那么在前端控制台通过js先获取链接。将程序copy到控制台执行
// 这个links在控制台的时候,为自己获取的htmlelement对象。
var links = [];
var urls = [];
for (var i = 0; i < links.length; i++) {
var el = links[i];
var link = el.children[0].getAttribute("href");
urls.push(link);
}
console.log(urls);
复制代码
2 写Java程序,做好准备工作,先添加依赖
<dependency>
<groupId>io.github.bonigarcia</groupId>
<artifactId>webdrivermanager</artifactId>
<version>3.4.0</version>
<!--<scope>test</scope>-->
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.59</version>
</dependency>
复制代码
3 规划Java程序,需要有个登录的程序,以及检查是否登录的
/**
* 用于在登录之后,通知爬取线程爬取数据
*/
static Object lock = new Object();
/**
* 检查浏览器是否登录, 判断是否登录的方式,每个网站都不同,找到判断的方式
*/
private static class LoginCheckThread extends Thread {
@Override
public void run() {
try {
Thread.sleep(5 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
while (true) {
try {
Thread.sleep(5 * 1000);
List<WebElement> element = driver.findElements(By.className("Om1BnS6m_0"));
if (element == null || element.size() == 0) {
continue;
}
String userInfo = element.get(0).getText();
if (userInfo.contains("登录")) {
System.out.println("用户暂未登录");
} else {
System.out.println("登录成功");
synchronized (lock) {
lock.notifyAll();
}
break;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
复制代码
4 爬取数据的部分
/**
* 爬取数据
* 1 首先等待登录线程
* 2 关于如何保存,每个人的方式都不同
* @throws InterruptedException
* @throws IOException
*/
private static void extract() throws InterruptedException, IOException {
synchronized (lock) {
System.out.println("锁定");
lock.wait();
System.out.println("已经解锁");
for (int i = 0; i < urls.length; i++) {
driver.get(PREFIX + urls[i]);
Thread.sleep(5 * 1000);
System.out.println(driver.getTitle());
File file = new File("/Users/aihe/Downloads/protocolv2/" + driver.getTitle() + ".jpg");
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file));
bufferedWriter.write(driver.findElement(By.tagName("body")).getText());
bufferedWriter.close();
// 如果有需要用于保存快照
// File screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
// FileUtils.copyFile(screenshot,file);
}
}
}
复制代码
5 主程序
/**
* 登录线程与爬取数据线程不在同一个程序之中
* 最后是否浏览器资源
* @param args
*/
public static void main(String[] args) {
WebDriverManager.chromedriver().setup();
driver = new ChromeDriver();
try {
login();
extract();
} catch (Exception e) {
e.printStackTrace();
} finally {
driver.quit();
System.out.println("end");
}
}
复制代码
6 效果
最后
这里就是提供一个思路,具体怎么拿数据到时候根据自己的需求来,不过像爬数据是一个很不错的用来练习多线程的方式。
- 公开的网站,用多线程爬取数据
- 需要登录的网站,注意控制频率,登录线程与爬取线程的协调
仅做抛转引玉,扩展一下:
- 有的时候可能爬取下来的内容还是被限制了一次,html中的内容依赖js,如果有文字的话,可以试着使用pandoc转化html文件为其它格式的。
pandoc -s xxx.html -o test.text
复制代码