不知道算不算違規,不過還是記錄一下,屬於比較有用的小技巧。有的網站需要登錄,才能查看其裏面的東西。有時候如果只是文字的東西,想要分享出去。比如說極客時間的專欄。
那就爬取內容保存下來吧。
方法
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