爬取需要登錄信息的網站

不知道算不算違規,不過還是記錄一下,屬於比較有用的小技巧。有的網站需要登錄,才能查看其裏面的東西。有時候如果只是文字的東西,想要分享出去。比如說極客時間的專欄。

那就爬取內容保存下來吧。

方法

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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章