使用scrapy搭建大型爬蟲系統

seozed發表於2017-01-15

最近新專案準備啟動,在開始前內容、詞庫這些都需要提前做好準備,所以就有了這篇文章。
在開始動手,看了下行業核心詞排在首頁的站,發現內容都多得不要不要的,各種亂七八糟的頻道、頁面模板,心想,如果每個網站、每套頁面都寫一套採集模板的話,那簡直要累死。

所以,這次,玩點不一樣的。

首先,根據需求,採集一個行業的文章內容,可以拆分為兩個模組:

  1. 爬蟲系統:主要負責在浩瀚的網際網路上,找到有內容價值的頁面並且把頁面抓取回來。涉及到URL去重、爬蟲策略深度、廣度一些雜事。
  2. 內容處理系統:主要負責處理爬蟲抓回來的內容,並從裡面提取出內容。

正文提取

以前在用印象筆記的時候,自帶的一些小外掛就很好用,只需要在瀏覽器上點一個按鈕,就會自動提取出當前網頁的正方,並且儲存到筆記庫裡面。
在網上找了下,發現已經有很多現成的解決方案了,而且解決的方案/演算法也很有意思。就是基於DOM樹來處理的。
凡是DOM節點 name 或ID帶有article、content、body的,加權重值。
DOM節點name或ID帶有foot、comment、menu……的,降權。
經過一輪遍歷後,把得分最高的節點提取出來,作為頁面正文所在的節點。
演算法參考:python-readability
測試了下,識別率還是挺高的,80%以上的成功率應該有。

4376297-eacac457ef563fa1.png
提取正文效果

抓取系統

爬蟲製作上面,選擇了一直以來,用的比較順手的scrapy做框架,程式碼如下:

# -- coding: utf-8 --  
import scrapy  
from scrapy import Request  
from scrapy.linkextractors import LinkExtractor  
from scrapy.spiders import CrawlSpider, Rule  
  
class LinkSpider(CrawlSpider):  
    name = 'link'  
    alloweddomains =   
    starturls =   
    rules = (  
        Rule(LinkExtractor(allow=r'\.htm', deny='baidu\.com'), callback='parseitem', follow=True),  
    )  
  
    def startrequests(self):  
        keywords = open('keywords.txt').readlines()  
        baseurlbaidu = 'https://www.baidu.com/s?rn=50&tn=baidulocal&wd=0&pn=1'  
        for kw in keywords:  
            # 構造百度搜尋結果頁URL  
            for pn in range(0,700,50):  
                yield Request(baseurlbaidu.format(kw,pn))  
  
    def parsestarturl(self, response):  
        """從種子頁面提取URL作為初始連結"""  
        links = response.css('td.f a:first-childattr(href)').extract()  
        for link in links:  
            yield Request(url=link)  
  
    def parseitem(self, response):  
        """提取符合要求的網站內頁"""  
        return response.url  

程式碼有木有非常簡單(滑稽),種子頁面是從百度搜尋結果頁開始的,為了減少網路請求次數,把百度結果頁的網站數量從預設的10個,改成了50,同時使用了無廣告版的百度,URL是沒有經過加密的。

到這裡,基本上一個簡單的行業內容採集爬蟲就完成了,隨意測試了下scrapy的速度,發現在我的 I5機器上,每分鐘可以抓3356個頁面,這還只是單機單程式,鵝妹子嚶~~

參考資料:
如何實現有道雲筆記的網頁正文抓取功能?

相關文章