WebMagic使用說明-基本的爬蟲

本文是WebMagic文檔的一部分。系列文章寫完後,會整合到WebMagic新版文檔中。css

3. 基本的爬蟲

3.1 實現PageProcessor

在WebMagic裏,實現一個基本的爬蟲只須要編寫一個類,實現PageProcessor接口便可。這個類基本上包含了抓取一個網站,你須要寫的全部代碼。html

以以前的GithubRepoPageProcessor爲例,我將PageProcessor的定製分爲三個部分,分別是爬蟲的配置、頁面元素的抽取和連接的發現。前端

public class GithubRepoPageProcessor implements PageProcessor {

    // 部分一:抓取網站的相關配置,包括編碼、抓取間隔、重試次數等
    private Site site = Site.me().setRetryTimes(3).setSleepTime(1000);

    @Override
    // process是定製爬蟲邏輯的核心接口,在這裏編寫抽取邏輯
    public void process(Page page) {
        // 部分二:定義如何抽取頁面信息,並保存下來
        page.putField("author", page.getUrl().regex("https://github\\.com/(\\w+)/.*").toString());
        page.putField("name", page.getHtml().xpath("//h1[@class='entry-title public']/strong/a/text()").toString());
        if (page.getResultItems().get("name") == null) {
            //skip this page
            page.setSkip(true);
        }
        page.putField("readme", page.getHtml().xpath("//div[@id='readme']/tidyText()"));

        // 部分三:從頁面發現後續的url地址來抓取
        page.addTargetRequests(page.getHtml().links().regex("(https://github\\.com/\\w+/\\w+)").all());
    }

    @Override
    public Site getSite() {
        return site;
    }

    public static void main(String[] args) {

        Spider.create(new GithubRepoPageProcessor())
                //從"https://github.com/code4craft"開始抓
                .addUrl("https://github.com/code4craft")
                //開啓5個線程抓取
                .thread(5)
                //啓動爬蟲
                .run();
    }
}

3.1.1 爬蟲的配置

第一部分關於爬蟲的配置,包括編碼、抓取間隔、超時時間、重試次數等,也包括一些模擬的參數,例如User Agent、cookie,以及代理的設置,咱們會在第5章-「爬蟲的配置」裏進行介紹。在這裏咱們先簡單設置一下:重試次數爲3次,抓取間隔爲一秒。java

3.1.2 頁面元素的抽取

第二部分是爬蟲的核心部分:對於下載到的Html頁面,你如何從中抽取到你想要的信息?WebMagic裏主要使用了三種抽取技術:XPath、正則表達式和CSS選擇器。git

  1. XPathgithub

    XPath原本是用於XML中獲取元素的一種查詢語言,可是用於Html也是比較方便的。例如:web

    page.getHtml().xpath("//h1[@class='entry-title public']/strong/a/text()")

    這段代碼使用了XPath,它的意思是「查找全部class屬性爲'entry-title public'的h1元素,並找到他的strong子節點的a子節點,並提取a節點的文本信息」。 對應的Html是這樣子的:正則表達式

    xpath-html

  2. CSS選擇器數據庫

    CSS選擇器是與XPath相似的語言。若是你們作過前端開發,確定知道$('h1.entry-title')這種寫法的含義。客觀的說,它比XPath寫起來要簡單一些,可是若是寫複雜一點的抽取規則,就相對要麻煩一點。cookie

  3. 正則表達式

    正則表達式則是一種通用的文本抽取語言。

    page.addTargetRequests(page.getHtml().links().regex("(https://github\\.com/\\w+/\\w+)").all());

    這段代碼就用到了正則表達式,它表示匹配全部"https://github.com/code4craft/webmagic"這樣的連接。

XPath、CSS選擇器和正則表達式的具體用法會在第4章「抽取工具詳解」中講到。

3.1.3 連接的發現

有了處理頁面的邏輯,咱們的爬蟲就接近完工了!

可是如今還有一個問題:一個站點的頁面是不少的,一開始咱們不可能所有列舉出來,因而如何發現後續的連接,是一個爬蟲不可缺乏的一部分。

page.addTargetRequests(page.getHtml().links().regex("(https://github\\.com/\\w+/\\w+)").all());

這段代碼的分爲兩部分,page.getHtml().links().regex("(https://github\\.com/\\w+/\\w+)").all()用於獲取全部知足"(https://github\.com/\w+/\w+)"這個正則表達式的連接,page.addTargetRequests()則將這些連接加入到待抓取的隊列中去。

3.2 使用Selectable的鏈式API

Selectable相關的鏈式API是WebMagic的一個核心功能。使用Selectable接口,你能夠直接完成頁面元素的鏈式抽取,也無需去關心抽取的細節。

在剛纔的例子中能夠看到,page.getHtml()返回的是一個Html對象,它實現了Selectable接口。這個接口包含一些重要的方法,我將它分爲兩類:抽取部分和獲取結果部分。

3.2.1 抽取部分API:

方法 說明 示例
xpath(String xpath) 使用XPath選擇 html.xpath("//div[@class='title']")
$(String selector) 使用Css選擇器選擇 html.$("div.title")
$(String selector,String attr) 使用Css選擇器選擇 html.$("div.title","text")
css(String selector) 功能同$(),使用Css選擇器選擇 html.css("div.title")
links() 選擇全部連接 html.links()
regex(String regex) 使用正則表達式抽取 html.regex("<div>(.*?)</div>")
regex(String regex,int group) 使用正則表達式抽取,並指定捕獲組 html.regex("<div>(.*?)</div>",1)
replace(String regex, String replacement) 替換內容 html.replace("<script>.*</script>","")

這部分抽取API返回的都是一個Selectable接口,意思是說,抽取是支持鏈式調用的。下面我用一個實例來說解鏈式API的使用。

例如,我如今要抓取github上全部的Java項目,這些項目能夠在https://github.com/search?l=Java&p=1&q=stars%3A%3E1&s=stars&type=Repositories搜索結果中看到。

爲了不抓取範圍太寬,我指定只從分頁部分抓取連接。這個抓取規則是比較複雜的,我會要怎麼寫呢?

selectable-chain-ui

首先看到頁面的html結構是這個樣子的:

selectable-chain

那麼我能夠先用CSS選擇器提取出這個div,而後在取到全部的連接。爲了保險起見,我再使用正則表達式限定一下提取出的URL的格式,那麼最終的寫法是這樣子的:

List<String> urls = page.getHtml().css("div.pagination").links().regex(".*/search/\?l=java.*").all();

而後,咱們能夠把這些URL加到抓取列表中去:

List<String> urls = page.getHtml().css("div.pagination").links().regex(".*/search/\?l=java.*").all();
page.addTargetRequests(urls);

是否是比較簡單?除了發現連接,Selectable的鏈式抽取還能夠完成不少工做。咱們會在第9章示例中再講到。

3.2.2 獲取結果的API:

當鏈式調用結束時,咱們通常都想要拿到一個字符串類型的結果。這時候就須要用到獲取結果的API了。咱們知道,一條抽取規則,不管是XPath、CSS選擇器或者正則表達式,總有可能抽取到多條元素。WebMagic對這些進行了統一,你能夠經過不一樣的API獲取到一個或者多個元素。

方法 說明 示例
get() 返回一條String類型的結果 String link= html.links().get()
toString() 功能同get(),返回一條String類型的結果 String link= html.links().toString()
all() 返回全部抽取結果 List<String> links= html.links().all()
match() 是否有匹配結果 if (html.links().match()){ xxx; }

例如,咱們知道頁面只會有一條結果,那麼能夠使用selectable.get()或者selectable.toString()拿到這條結果。

這裏selectable.toString()採用了toString()這個接口,是爲了在輸出以及和一些框架結合的時候,更加方便。由於通常狀況下,咱們都只須要選擇一個元素!

selectable.all()則會獲取到全部元素。

好了,到如今爲止,在回過頭看看3.1中的GithubRepoPageProcessor,可能就以爲更加清晰了吧?指定main方法,已經能夠看到抓取結果在控制檯輸出了。

3.3 保存結果

好了,爬蟲編寫完成,如今咱們可能還有一個問題:我若是想把抓取的結果保存下來,要怎麼作呢?WebMagic用於保存結果的組件叫作Pipeline。例如咱們經過「控制檯輸出結果」這件事也是經過一個內置的Pipeline完成的,它叫作ConsolePipeline。那麼,我如今想要把結果用Json的格式保存下來,怎麼作呢?我只須要將Pipeline的實現換成"JsonFilePipeline"就能夠了。

public static void main(String[] args) {

        Spider.create(new GithubRepoPageProcessor())
                //從"https://github.com/code4craft"開始抓
                .addUrl("https://github.com/code4craft")
                .addPipeline(new JsonFilePipeline("D:\webmagic\"))
                //開啓5個線程抓取
                .thread(5)
                //啓動爬蟲
                .run();
    }

這樣子下載下來的文件就會保存在D盤的webmagic目錄中了。

經過定製Pipeline,咱們還能夠實現保存結果到文件、數據庫等一系列功能。這個會在第7章「抽取結果的處理」中介紹。

至此爲止,咱們已經完成了一個基本爬蟲的編寫,也具備了一些定製功能。

相關文章
相關標籤/搜索