Java 爬蟲學習


Java爬蟲領域最強大的框架是JSoup:可直接解析具體的URL地址(即解析對應的HTML),提供了一套強大的API,包括可以通過DOM、CSS選擇器,即類似jQuery方式來取出和操作數據。主要功能有:

  • 從給定的URL、文件、字符串中,獲得HTML代碼。
  • 然后通過DOM、CSS選擇器(類jQuery方式)來查找、取出數據:先找到HTML元素,然后獲取其屬性、文本等。

API初步學習:

上面提到了三種方式,獲取HTML文檔(JSoup的Document對象的結構是:<html><head></head><body></body></html>):

1、通過字符串:String html="hello"; Document doc = Jsoup.parse(html);//(此時JSoup會把hello放在doc對象中的body中。如果字符串是一個完整的html文檔,那么doc對象將以字符串的html結構為准)。

2、獲取URL的HTML文檔(注意:這種方式下,只有當調用get或post方法時,才真正發送請求):

//通過URL獲得連接:Connection對象 Connection conn = Jsoup.connect("http://www.baidu.com"); //以下為主要方法,多數返回Connection conn.data("query", "Java"); // 請求參數 conn.userAgent("I ’ m jsoup"); // 設置 User-Agent conn.cookie("auth", "token"); // 設置 cookie conn.timeout(3000); // 設置連接超時時間 //發送請求,獲得HTML文檔:Document對象 Document doc = conn.get(); Document doc = conn.post();

獲取元素:

1、通過DOM方式(與純JavaScript方式相同):

//獲取文檔級信息,如: String title = doc.title(); //獲取單個HTML元素,如:<div id="content"></div> Element content = doc.getElementById("content"); //獲取多個元素,如:<a href="http://www.qunyh.cn"></a> <a href="http://cn.bing.com"></a> Elements links = doc.getElementsByTag("a");

2、類似於jQuery的方式,這里是將$換成了select方法:

//select的參數是類似於jQuery的選擇器selector Elements allP = doc.select("p"); Element firstP = allP.first(); Element oneP = allP.get(1);//從0開始 //操作元素: for (Element p : allP) { //操縱元素:這里就類似於jQuery String text = p.text(); }

當然JSoup只是模仿jQuery的方便性,並不具備jQuery的所有功能,例如jQuery的插件肯定是無法在JSoup中使用。因此如果對JS掌握很好,選擇Node.js+MongoDB來處理就比較有優勢(即相互之間的支持度比較大)。如果熟悉Java,那么就可以選擇JSoup+MySql+Quartz,也是非常好用的(全程java實現,省心方便),再配合Java調度器Quartz,就可實現一個完整的爬蟲了。

 

爬蟲框架 Gecco

Gecco 是用 Java 實現的,輕量化,面向主題的爬蟲,與 Nutch 這種面向搜索引擎的通用爬蟲不同:

  • 通用爬蟲通常關注三個問題:下載、排序、索引。
  • 主題爬蟲則關注:下載、內容抽取、靈活的業務邏輯處理。

Gecco 的目標:提供一個完善的主題爬蟲框架:簡化下載和內容抽取的開發;利用管道過濾器模式,提供靈活的內容清洗和持久化處理模式。故而開發可以集中精力在業務主題方面的邏輯、內容處理。

學習一個框架,首先要了解到它的用途何在:

  • 簡單易用,使用 jQuery 的 Selector 風格抽取元素。
  • 支持頁面中的異步 Ajax 請求
  • 支持頁面中的 JavaScript 變量抽取。
  • 利用 Redis 實現分布式抓取,可參考 Gecco-Redis。
  • 支持下載時 UserAgent 隨機選取。
  • 支持下載代理服務器隨機選取。
  • 支持結合 Spring 開發業務邏輯,參考 Gecco-Spring。
  • 支持 htmlUnit 擴展,參考 Gecco-htmlUnit。
  • 支持插件擴展機制。

一分鍾你就可以寫一個簡單爬蟲

先將一個基本的程序撂出來(內容以 json 格式在 console 輸出):

@Gecco(matchUrl = "https://github.com/{user}/{project}", pipelines = "consolePipeline")
public class Tester implements HtmlBean {

    private static final long serialVersionUID = 4538118606557597719L;
    
    @RequestParameter("user")
    private String user;
    @RequestParameter("project")
    private String project;
    
    @Text
    @HtmlField(cssPath = ".repository-meta-content .mr-2")
    private String title;
    
    @Text
    @HtmlField(cssPath = ".pagehead-actions li:nth-child(2) .social-count")
    private int star;
    
    @Text
    @HtmlField(cssPath = ".pagehead-actions li:nth-child(3) .social-count")
    private int fork;
    
    @Html
    @HtmlField(cssPath = ".entry-content")
    private String readme;

  // 此處略去 getter and setter

    public static void main(String[] args) {
        GeccoEngine.create()
    // Geeco搜索的包路徑:即使用了@Geeco注解的類所在的包路徑
        .classpath("com.jackie.json.controller")
    // 最開始抓取的頁面地址:簡單的就是一個,當然也有可變參數列表的重載(即接受多個url地址參數)
        .start("https://github.com/xtuhcy/gecco")
    // 開啟幾個爬蟲線程
        .thread(1)
    // 對每個爬蟲而言,每次抓取完一個請求之后,再次請求的間隔時間
        .interval(2000)
    // 與上面的start方法用途不同,用於啟動爬蟲線程:start方法非阻塞式運行爬蟲;run方法則是阻塞式
        .start();
    }
}

代碼說明:

  • 首先爬蟲類 implements 了一個 HtmlBean 接口:說明了該爬蟲是一個解析 html 頁面的爬蟲(還可以支持 json 格式的解析,即 JsonBean)。
  • @Gecco 注解:告知爬蟲,匹配的 url 格式(matchUrl)和內容抽取后的 bean 處理類 pipelines(采用管道過濾器模式,可以指定多個 pipeline 處理類。例如指定為 consolePipeline,則輸出在 console 中)。
  • @RequestParamter:注入請求過的 url 中匹配的請求參數,如@RequestParamer("user") 則匹配到 url 中的 {user}。
  • @HtmlField:表示抽取 html 中的元素,其中 cssPath 采用類似於 jQuery 的 css selector 的方式選取元素。
  • @Text:表示獲取 @HtmlField 抽取元素的 Text 內容。@Html:表示獲取對應的 Html 內容(默認 @Html)。注意的是:若抽取的元素中沒有 html 代碼,則不能指定為 @Html,否則會報錯;若有 html 代碼,則不能指定為 @Text,否則不能獲取任何內容,將會輸出為空字符串。
  • GeccoEngine:爬蟲引擎類,通過 create() 初始化,通過 start() / run() 運行。還可以配置一些啟動參數,如上代碼所示,后面也會詳細介紹。

軟件總體架構(爬蟲引擎的架構)

如圖:

簡單介紹:

  • GeccoEngine:爬蟲引擎,每個爬蟲引擎最好是一個獨立進程。在分布式爬蟲場景下,建議每台爬蟲服務器(物理機、虛擬機)只運行一個 GeccoEngine。爬蟲引擎主要包括Scheduler、Downloader、Spider、SpiderFactory、PipelineFactory 5個模塊。
  • Scheduler:

GeccoEngine 的詳細介紹

Gecco 如何運行,下面是最基本的啟動方法:

GeccoEngine.create()
    // classpath是必填項
    .classpath("com.geccocrawler.gecco.demo")
    // 初始請求地址
    .start("https://github.com/xtuhcy/gecco")
    .start();

GeccoEngine 的基本配置:

  • loop(boolean):表示是否循環抓取,默認為 false。
  • thread(int):表示開啟的爬蟲線程數量,默認是1。值得注意的是,線程數量要小於等於 start 方法中指定的 url 數量。
  • interval(int):表示請求間隔時間,單位是毫秒 ms。假設設置的值是 x 秒,那么系統會把間隔時間隨機在 [ x - 1, x + 1] 這個區間內(1 即指 1 秒)。例如,設置為 2000 ms,那么最終的間隔時間將會在 1000 ms ~ 3000 ms 內隨機。
  • mobile(bollean):表示使用移動端還是 pc 端的 UserAgent。默認為 false,使用 pc 端的 UserAgent。
  • debug(boolean):是否開啟 debug 模式,即如果開啟 debug 模式,那么將會在控制台輸出 JSoup 元素抽取的日志 —— 如果出了問題才能在日志中找到原因。
  • pipelineFactory(PipelineFactory):設置自定義的 pipelineFactory,通過實現 PipelineFactory 接口,自定義 pipelineFactory 類。
  • scheduler(Scheduler):設置自定義的請求隊列管理器 Scheduler。

非阻塞式啟動和阻塞式啟動

  • start():非阻塞式啟動,即 GeccoEngine 會單獨啟動線程運行。推薦以該方式運行,線程模式如下:MainThread ——> GeccoEngineThread ——> SpiderThread。
  • run():阻塞式啟動,GeccoEngine 在主線程中啟動並運行。非循環模式 GeccoEngine 需要等待其他爬蟲線程運行完畢后,run() 方法才會退出。線程模型如下:GeccoEngineThread(即在主線程中)——> SpiderThread。

Gecco 如何匹配 URL

matchUrl 的作用:告知 Gecco,這種格式的 url 對應的網頁將會被渲染成當前指定的 SpiderBean(如包裝成 HtmlBean 的對象)。matchUrl 模糊匹配模式中的 {} 可以匹配任意非空字符串,除了 "/"。

如果不寫 matchUrl,則為任意匹配模式,那么任意的 url 都會被匹配,可用作通用爬蟲,例如官網給出的 CommonClawer

說說下載

下載引擎:爬蟲最基本的能力就是發起 http 請求,然后下載網頁。Gecco 默認采用 httpClientDownloader(httpclient4)作為下載引擎。通過實現 downloader 接口,可以自定義設置下載引擎。例如:

@Gecco(matchUrl="https://github.com/{user}/{project}", pipelines="consolePipeline", downloader="htmlUnitDownloder")

HttpRequest 和 HttpReponse:一個表示下載請求,一個表示下載響應。爬蟲會模擬瀏覽器,將下載請求包裝成 GET 或 POST 請求,分別對應 HttpGetRequest、HttpPostRequest 類。

Gecco 的請求可以支持:

  • 模擬 userAgent,並支持 userAgent 的隨機輪詢。在 classpath 的根目錄下定義 userAgents 文件,每行代表一個 UserAgent。
  • cookie 定義:request.addCookie(String name, String value),可模擬用戶登錄。
  • 代理服務器的隨機輪詢。在 classpath 的根目錄下定義 proxys 文件,每行代表一個代理服務器的主機和端口,如 127.0.0.1:8888。

下載地址管理

爬蟲通常需要一個請求隊列管理器 Scheduler,負責下載地址的管理:

Gecco 使用 StartScheduler 管理初始地址,StartScheduler 內部采用一個阻塞的 FIFO 隊列(即嚴格的 FIFO,一個線程抓取完一個地址之后,才會去抓另一個地址);初始地址通常會派生出很多其他待抓取的地址(例如列表頁是初始地址的集合頁面,詳情頁是派生的地址),並用 SpiderScheduler 管理派生的地址,SpiderScheduler 內部采用線程安全的非阻塞 FIFO 隊列(不嚴格的先進先出)。

這種設計使得 Gecco 對初始地址采用了深度遍歷(理解還不夠深刻)?的策略;對派生的地址采用了廣度遍歷的策略(如何派生參考下面的 “派生地址“)。此外,Gecco 的分布式抓取也是通過 Scheduler 完成,准確的說是通過實現不同的StartScheduler,來將初始地址分配到不同的服務器中來完成;Gecco 分布式抓取默認采用 redis 來實現,具體參考 gecco-redis 項目。

派生地址

Gecco 派生地址的方式有兩種:

一是使用注解,如下:

@Href(click = true)
@HtmlField(cssPath = "...")
private String detailUrl;

派生地址如同其他內容一樣,需要使用 @HtmlField 注解,從初始地址的頁面中抽取。不同的是 @Href 注解,當參數 click 為 true 時,抽取出來的 url 會繼續抓取。

二是顯式的加入 SpiderScheduler 的方法,如:

DeriveSchedulerContext.into(request.subRequest("subUrl"));

上面的 HttpRequest 對象可以通過 @Request 注解獲得,然后通過該對象的 subRequest 方法生成對派生地址的請求,然后加入到 SpiderScheduler 隊列中。可以在相應的 pipeline 類中對請求的增加進行過濾。

初始地址的配置

可以在 classpath 根目錄下,放置 starts.json 配置文件,可配置多個初始地址,如下:

[
    {
        "charset": "GBK",
        "url": "http://item.jd.com/123.html"
    },
    {
        "url": "https://github.com/xtuhcy/gecco"
    }
]

此外,如果要設置的初始地址不多,則可以如上面的程序,直接在 GeccoEngine.start(String ...) 方法中添加。

BeforeDownload 和 AfterDownload

有一些特殊場景,可能會需要在下載的前后做一些處理,處理之后再傳遞給 pipeline 輸出。如下:

@GeccoClass(CruiseDetail.class)
public class CruiseDetailBeforeDownload implements BeforeDownload {

    @Override
    public void process(HttpRequest request) {

    }

}

上面這個類是針對 CruiseDetail 這個 bean 的下載之前的自定義預處理。同理,下載后如下:

@GeccoClass(CruiseRedirect.class)
public class CruiseRedirectAfterDownload implements AfterDownload {

    @Override
    public void process(HttpRequest request, HttpResponse response) {
        
    }

}

使用 HtmlUnit 作為下載引擎

Gecco 通過擴展 downloader 實現了對 htmlUnit 的支持,如下(使用詳情參照 gecco-htmunit 項目):

<dependency>
    <groupId>com.geccocrawler</groupId>
    <artifactId>gecco-htmlunit</artifactId>
    <version>1.0.9</version>
</dependency>

 

 

 

找資料的時候發現了新的、不錯的爬蟲框架(以后有時間嘗試):
Gecco Crawler:
Gecco是一款用java語言開發的輕量化的易用的網絡爬蟲,不同於Nutch這樣的面向搜索引擎的通用爬蟲,Gecco是面向主題的爬蟲。
https://github.com/xtuhcy/gecco
https://xtuhcy.gitbooks.io/geccocrawler/content/index.html
https://my.oschina.net/u/2336761/blog/688534
模板代碼生成器:J2ee template(由JSoup開發而成,可借鑒其如何開發的爬蟲):
https://www.oschina.net/p/jeetemp


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM