1. 程式人生 > >Java 爬蟲遇上資料非同步載入,試試這兩種辦法!

Java 爬蟲遇上資料非同步載入,試試這兩種辦法!

這是 Java 爬蟲系列博文的第三篇,在上一篇 Java 爬蟲遇到需要登入的網站,該怎麼辦? 中,我們簡單的講解了爬蟲時遇到登入問題的解決辦法,在這篇文章中我們一起來聊一聊爬蟲時遇到資料非同步載入的問題,這也是爬蟲中常見的問題。

現在很多都是前後端分離專案,這會使得資料非同步載入問題更加突出,所以你在爬蟲時遇到這類問題不必驚訝,不必慌張。對於這類問題的解決辦法總體來說有以下兩種:

1、內建一個瀏覽器核心

內建瀏覽器就是在抓取的程式中,啟動一個瀏覽器核心,使我們獲取到 js 渲染後的頁面,這樣我們就跟採集靜態頁面一樣了。這種工具常用的有以下三種:

  • Selenium
  • HtmlUnit
  • PhantomJs

這些工具都能幫助我們解決資料非同步載入的問題,但是他們都存在缺陷,那就是效率不高而且不穩定。

2、反向解析法

什麼是反向解析法呢?我們 js 渲染頁面的資料是通過 Ajax 的方式從後端獲取的,我們只需要找到對應的 Ajax 請求連線就 OK,這樣我們就獲取到了我們需要的資料,反向解析法的好處就是這種方式獲取的資料都是 json 格式的資料,解析起來也比較方便,另一個好處就是相對頁面來說,介面的變化概率更小。同樣它有兩個不足之處,一個是在 Ajax 時你需要有耐心有技巧,因為你需要在一大推請求中找到你想要的,另一個不足的地方就是對 JavaScript 渲染的頁面束手無策。

上面就是非同步資料載入的兩種解決辦法,為了加深大家的理解和在專案中如何使用,我以採集網易要聞為例,網易新聞地址:https://news.163.com/

。利用上訴的兩種方式來獲取網易要聞的新聞列表。網易要聞如下:

內建瀏覽器 Selenium 方式

Selenium 是一個模擬瀏覽器,進行自動化測試的工具,它提供一組 API 可以與真實的瀏覽器核心互動。在自動化測試上使用的比較多,爬蟲時解決非同步載入也經常使用它,我們要在專案中使用 Selenium ,需要做兩件事:

  • 1、引入 Selenium 的依賴包,在 pom.xml 中新增
<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
<dependency>
    <groupId>org.seleniumhq.selenium</groupId>
    <artifactId>selenium-java</artifactId>
    <version>3.141.59</version>
</dependency>
  • 2、下載對應的 driver,例如我下載的 chromedriver,下載地址為:https://npm.taobao.org/mirrors/chromedriver/,下載後,需要將 driver 的位置寫到 Java 的環境變數裡,例如我直接放在專案下,所以我的程式碼為:
    System.getProperties().setProperty("webdriver.chrome.driver", "chromedriver.exe");

完成上面兩步之後,我們就可以來編寫使用 Selenium 採集網易要聞啦。具體程式碼如下:

/**
 * selenium 解決資料非同步載入問題
 * https://npm.taobao.org/mirrors/chromedriver/
 *
 * @param url
 */
public void selenium(String url) {
    // 設定 chromedirver 的存放位置
    System.getProperties().setProperty("webdriver.chrome.driver", "chromedriver.exe");
    // 設定無頭瀏覽器,這樣就不會彈出瀏覽器視窗
    ChromeOptions chromeOptions = new ChromeOptions();
    chromeOptions.addArguments("--headless");

    WebDriver webDriver = new ChromeDriver(chromeOptions);
    webDriver.get(url);
    // 獲取到要聞新聞列表
    List<WebElement> webElements = webDriver.findElements(By.xpath("//div[@class='news_title']/h3/a"));
    for (WebElement webElement : webElements) {
        // 提取新聞連線
        String article_url = webElement.getAttribute("href");
        // 提取新聞標題
        String title = webElement.getText();
        if (article_url.contains("https://news.163.com/")) {
            System.out.println("文章標題:" + title + " ,文章連結:" + article_url);
        }
    }
    webDriver.close();
}

執行該方法,得到結果如下:

我們使用 Selenium 已經正確的提取到了網易要聞的列表新聞。

反向解析法

反向解析法就是獲取到 Ajax 非同步獲取資料的連結,直接獲取到新聞資料。如果沒有技巧的話,查詢 Ajax 的過程將非常痛苦,因為一個頁面載入的連結太多了,看看網易要聞的 network:

有幾百條的請求,該如何查詢到是哪條請求獲取的要聞資料呢?你不嫌麻煩的話,可以一個一個的去點,肯定能夠查詢到的,另一種快捷的辦法是利用 network 的搜尋功能,如果你不知道搜尋按鈕,我在上圖已經圈出來啦,我們在要聞中隨便複製一個新聞標題,然後檢索一下,就可以獲取到結果,如下圖所示:

這樣我們就快速的獲取到了要聞資料的請求連結,連結為:https://temp.163.com/special/00804KVA/cm_yaowen.js?callback=data_callback,訪問該連結,檢視該連結返回的資料,如下圖所示:

從資料我們可以看出,我們需要的資料都在這裡啦,所以我們只需要解析這段資料接可以啦,要從這段資料中解析出新聞標題和新聞連結,有兩種方式,一種是正則表示式,另一種是將該資料轉成 json 或者 list。這裡我選擇第二種方式,利用 fastjson 將返回的資料轉換成 JSONArray 。所以我們是要引入 fastjson ,在 pom.xml 中引入 fastjson 依賴:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.59</version>
</dependency>

除了引入 fastjson 依賴外,我們在轉換前還需要對資料進行簡單的處理,因為現在的資料並不符合 list 的格式,我們需要去掉 data_callback( 和最後面的 )。具體反向解析獲取網易要聞的程式碼如下:

/**
 * 使用反向解析法 解決資料非同步載入的問題
 *
 * @param url
 */
public void httpclientMethod(String url) throws IOException {

    CloseableHttpClient httpclient = HttpClients.createDefault();
    HttpGet httpGet = new HttpGet(url);
    CloseableHttpResponse response = httpclient.execute(httpGet);
    if (response.getStatusLine().getStatusCode() == 200) {
        HttpEntity entity = response.getEntity();
        String body = EntityUtils.toString(entity, "GBK");
        // 先替換掉最前面的 data_callback(
        body = body.replace("data_callback(", "");
        // 過濾掉最後面一個 )右括號
        body = body.substring(0, body.lastIndexOf(")"));
        // 將 body 轉換成 JSONArray
        JSONArray jsonArray = JSON.parseArray(body);
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject data = jsonArray.getJSONObject(i);
            System.out.println("文章標題:" + data.getString("title") + " ,文章連結:" + data.getString("docurl"));
        }
    } else {
        System.out.println("處理失敗!!!返回狀態碼:" + response.getStatusLine().getStatusCode());
    }

}

編寫 main 方法,執行上面的方法,需要注意的地方是:這時候傳入的連結為https://temp.163.com/special/00804KVA/cm_yaowen.js?callback=data_callback 而不是 https://news.163.com/。得到如下結果:

兩種方法都成功的獲取到了網易要聞非同步載入的新聞列表,對於這兩種方法的選取,我個人的傾向是使用反向解析法,因為它的效能和穩定是都要比內建瀏覽器核心靠譜,但是對於一些使用 JavaScript 片段渲染的頁面,內建瀏覽器又更加靠譜。所以根據具體情況選擇吧。

希望這篇文章對你有所幫助,下一篇是關於 爬蟲IP 被封的問題。如果你對爬蟲感興趣,不妨關注一波,相互學習,相互進步

原始碼:原始碼

文章不足之處,望大家多多指點,共同學習,共同進步

最後

打個小廣告,歡迎掃碼關注微信公眾號:「平頭哥的技術博文」,一起進步吧。

相關推薦

Java 爬蟲資料非同步載入試試辦法

這是 Java 爬蟲系列博文的第三篇,在上一篇 Java 爬蟲遇到需要登入的網站,該怎麼辦? 中,我們簡單的講解了爬蟲時遇到登入問題的解決辦法,在這篇文章中我們一起來聊一聊爬蟲時遇到資料非同步載入的問題,這也是爬蟲中常見的問題。 現在很多都是前後端分離專案,這會使得資料非同步載入問題更加突出,所以你在爬蟲時遇

爬蟲知識點(ajax非同步載入JavaScript 動態重新整理phantomjs + selenium模擬登陸)

JavaScript JavaScript 是網路上最常用也是支持者最多的客戶端指令碼語言。它可以收集 使用者的跟蹤資料,不需要過載頁面直接提交表單,在頁面嵌入多媒體檔案,甚至執行網頁遊戲。 Ajax  當你訪問一個網頁時 滑鼠向下滑 資料不斷的更新而http網址沒有變

Redis的持久化機制包括RBD和AOF對於持久化方式各有優勢

plain 同步數據 pen toc 默認 ocl 好的 dfs 操作系統 RDB機制的策略 RDB持久化是指在指定的時間間隔內將內存中的數據和操作通過快照的方式保存到redis bin目錄下的一個默認名為 dump.rdb的文件,可以通過配置設置自動的快照持久化的

決定一個程式設計師能走多遠的不是年齡而是個原因

都說程式設計師有“中年危機”,說是程式設計師到了30-40歲就開始不吃香了,甚至會被企業淘汰。那麼事實真的是如此嗎?建議大家不妨看看那些程式設計師大腕,哪一個不是50歲上下的。 當然程式設計師是個很燒腦的工作,對自身技術要求很高,如果你到了中年而技術水平還停留在初級階段,那你被淘汰也沒什麼抱怨的

spark-shell 資料檔案 讀成 表 的方式 相對路徑hdfs dfs -ls

park SQL應用 Spark Shell啟動後,就可以用Spark SQL API執行資料分析查詢。 在第一個示例中,我們將從文字檔案中載入使用者資料並從資料集中建立一個DataFrame物件。然後執行DataFrame函式,執行特定的資料選擇查詢。 文字檔案cu

使用爬蟲抓取網站非同步載入資料

什麼是非同步載入? 向網站進行一次請求,一次只傳部分資料。如:有些網頁不需要點選下一頁,其內容也可以源源不斷地載入。 如何發現非同步載入? 1、開啟瀏覽器,右鍵選擇“檢查” 2、點選“Network”、“XHR” 這樣在網頁進行不斷下拉的過程中,顯示器

java爬蟲抓取資料儲存為excel檔案

下載jsoup jar包和poi jar包 City.java package dataToExcel; public class City { private String name; private String url;

當“資訊機器人”“商業智能”當“AI”“BI”會有怎樣的火花?

人工智能寫作 人工智能編輯 人工智能采集 新技術的誕生,往往是為了更好的服務人類,而這一過程,則離不開商業。何為商業智能?把企業中現有數據轉化為知識,幫助企業做出明智的業務經營決策的工具。 人工智能誕生後,在1958年,商業智能馬上進入人們的視野。但在過去,商業智能不能給出決策方案,也不能自動處理

vue 專案使用echarts非同步載入xAxis座標軸不顯示

1.安裝echarts cnpm install echarts -S 2.main.js // 引入echarts import echarts from 'echarts' Vue.prototype.$echarts = echarts 3.tool.vue <

【斑馬體育】說多都是淚當小個球員巨人球童原來最囧的竟然是TA

綠茵場上列隊出場、奏響國歌或主題曲的儀式,最讓球員尷尬,又能令現場球迷忍俊不禁,電視機前的觀眾甚至樂得開懷的一幕是什麼?那就是當小個球員遇上巨人球童。 今天凌晨英格蘭和瑞士在皇權球場一戰,原本只是一場普通平常的友誼賽。然而開場一路跟隨攝像機的鏡頭,竟然發現兩隊

當知識圖譜文字智慧處理會擦出怎樣的火花?

目前以理解人類語言為入口的認知智慧成為了人工智慧發展的突破點,而知識圖譜則是邁向認知智慧的關鍵要素。達觀資料在2018AIIA人工智慧開發者大會承辦的語言認知智慧與知識圖譜公開課上,三位來自企業和學術領域的專家分別從不同角度講述的知識圖譜的應用和發展。文字根據達觀資料副總裁王文廣演講內容《知識圖

Java實現圖片傳到伺服器並把傳的圖片讀取出來

題外話:推薦一個專注於Java開發的網站,做提升學習,價值閱讀: 同時,掃碼關注後端技術精選,回覆“學習資料”,領取100套小程式原始碼+小程式開發視訊和基本Java經典書籍電子版 在很多的網站都可以實現上傳頭像,可以選擇自己喜歡的圖片做頭像,從本地上傳,下次登入時可

解決echarts中多次資料非同步載入後觸發事件疊加問題

解決echarts中多次資料非同步載入後觸發事件疊加問題 問題描述 echarts中資料通過ajax等方式多次非同步載入資料後,當點選圖表中的同一位置時,其觸發事件也會隨之觸發多次。在官方的教程中有這樣一局原話“所有資料的更新都通過 setOption實現,你只需要定時獲

java爬蟲(使用jsoup設定代理抓取網頁內容)

jsoup 簡介 jsoup 是一款Java 的HTML解析器,可直接解析某個URL地址、HTML文字內容。它提供了一套非常省力的API,可通過DOM,CSS以及類似於jQuery的操作方法來

java——從鍵盤輸入一個年份並輸入一個月份(數字)輸出該月份有多少天

/* (程式頭部註釋開始) </p><p>* 程式的版權和版本宣告部分 * Copyright (c) 2011, 煙臺大學計算機學院學生 * 作 者: 李兆慶

java遞迴刪除資料夾demo刪除檔案目錄例子

private void deleteFile(File file) { if (file.exists()) {// 判斷檔案是否存在 if (file.is

Java 爬蟲遇到需要登入的網站該怎麼辦?

這是 Java 網路爬蟲系列博文的第二篇,在上一篇 Java 網路爬蟲,就是這麼的簡單 中,我們簡單的學習了一下如何利用 Java 進行網路爬蟲。在這一篇中我們將簡單的聊一聊在網路爬蟲時,遇到需要登入的網站,我們該怎麼辦? 在做爬蟲時,遇到需要登陸的問題也比較常見,比如寫指令碼搶票之類的,但凡需要個人資訊的都

java打印等腰三角形的方法(根據行數根據底邊長度)

triangle class [] 執行 next() result scanner 1-1 next 首先來看根據用戶輸入的底邊的長度判斷: 1 package cn.edu.nwpu.java; 2 3 import java.util.Scanner; 4

Java 程序員十面阿裏最終拿下阿裏 P7offer

offer 面試總結 str 菜鳥 並且 分享 計算 線程 如何 今天介紹小編的一個朋友,他現今有四年開發經驗了,前前後後為了進阿裏面試十次(阿裏旗下—螞蟻金服,天貓的offer都被hr因學歷而被拒,最後的菜鳥面幸運的被錄用,拿到P7offer,真正的“十面”阿裏!) 本文

天天 Java、C/C++編程語言你知道嗎?

計算機 scrip rip 生存 腳本 價值 本質 號稱 c++ "適者生存,優勝劣汰”,編程語言同樣適用。 世界上有超過 1500 種編程語言,雖然本質上都是對於最底層 0 與 1 的抽象和封裝,但是卻沒有哪一種編程語言可以解決所有的問題。當有新的問題領域出現時