[轉]使用scrapy進行大規模抓取

原文:http://www.yakergong.net/blog/archives/500javascript

使用scrapy有大概半年了,算是有些經驗吧,在這裏跟你們討論一下使用scrapy做爲爬蟲進行大規模抓取可能遇到的問題。咱們抓取的目標是教育網上的網站(目前主要針對.edu.cn和.cas.cn/.cass.cn域名),這半年裏抓取了百萬以上的url,其實百萬url的規模不算大,咱們一直在斷斷續續的修改,尚未開始全面的抓取。css

若是想了解scrapy的話,推薦pluskid的scrapy輕鬆定製網絡爬蟲,寫的很清晰。html

關於scrapy涉及的一些不太容易解決的性能問題,請參考使用scrapy進行大規模抓取(二)java

咱們對scrapy的修改是基於0.9 stable的(寫這篇文章時最新的release是0.10)。咱們爲了實現定製需求而進行的修改常常破壞了scrapy的代碼結構,因此這裏就不貼代碼了,有興趣的朋友能夠留言或者郵件討論。python

首先說下scrapy的定位吧,咱們看來它是爲抓取單一網站上固定格式的內容而設計的,好比抓取一個小說網站上的小說或者抓取一個電子商務網站上的商品。好在scrapy結構清晰,能夠很方便得修改它來實現更復雜的需求。要進行大規模的抓取,可能要修改scrapy以處理以下問題。react

快速的link extractor。python的SGMLParser實在是太慢了,使用SgmlLinkExtractor會讓爬蟲把大部分的時間都浪費在解析網頁上,最好本身寫一個link extractor(咱們基於lxml寫了一個,也能夠用soup之類的庫)。也能夠用正則表達式來寫link extractor,速度快,問題是不理解html語義,會把註釋裏的連接也包含進來。另外基於javascript重定向url也要在這裏提取出來。ajax

Spider Trap(?)。咱們解決這個問題的方法比較暴力。由於spider trap通常是由動態網頁實現的,因此咱們最開始的方案就是先經過url是否包含」?」來判斷一個網頁是不是動態網頁,而後取得不包含參數的url地址,對這個地址進行計數,設置一個閾值,超過閾值以後再也不抓取。這個方案遇到的困擾在於不少網站開啓了url rewrite,使得判別一個頁面是不是動態頁面很困難。如今的方法是把網頁按照所引用的css文件進行聚類,經過控制類裏最大能包含的網頁數量防止爬蟲進入trap後出不來,對不不含css的網頁會給一個penalty,限制它能產生的連接數量。這個辦法理論上不保證能避免爬蟲陷入死循環,可是實際上這個方案工做得挺好,由於絕大多數網頁都使用了css,動態網頁更是如此。之因此說着方法比較暴力是由於這兩種方法閾值都是寫死的,不能經過抓取的結果,網頁的類似度,網頁的重要性進行修改。正則表達式

增量抓取。一個針對多個網站的爬蟲很難一次性把全部網頁爬取下來,而且網頁也處於不斷更新的狀態中,爬取是一個動態的過程,爬蟲支持增量的抓取是很必要的。大概的流程就是關閉爬蟲時保存duplicate filter的數據,保存當前的request隊列,爬蟲啓動時導入duplicate filter,而且用上次request隊列的數據做爲start url。這裏還涉及scrapy一個稱得上bug的問題,一旦抓取隊列裏url過多,關閉scrapy須要好久,有時候要花費幾天的時間。咱們hack了scrapy的代碼,在接收到關閉命令後,保存duplicate filter數據和當前的request隊列和已抓取的url列表,而後調用twisted的reactor.stop()強制退出。當前的request隊列能夠經過scrapy.core.scheduler的pending_requests成員獲得。算法

高效數據存儲。抓取的頁面多了以後如何存儲就成了一個問題,按咱們的統計純html頁面的平均大小大概在20~30k之間,百萬的頁面抓下來以後佔用的硬盤空間大概是幾十G。ntfs和ext3這些文件系統在小文件過多以後效率都會比較低,須要優化存儲效率。咱們目前將頁面的url進行hash(sha1),以hash值做爲文件名,hash值的前幾位做爲目錄名存儲頁面,之後準備使用HDFS來存儲數據。服務器

scrapy的開發者仍是挺活躍的,這兩天就看到scrapy的blog上有專家寫關於ajax抓取的文章,ajax抓取是個挺常出現的問題。目前新版本的scrapy(0.10)支持持久化隊列支持增量抓取,爬蟲關閉過慢的問題也獲得了必定的解決,相信更多特性會逐步開發出來。

咱們目前的數據量其實也談不上大規模,針對這些問題的解決方式也不夠完美。這裏只是列舉一部分可能遇到的問題,實際的問題還有不少,好比編碼檢測/肯定網頁的重要性/按期更新。還有一個大問題就是內存泄露,在python裏檢查內存泄露很難,尤爲是對於工做在twisted上的這種持續工做的網絡程序,這個之後再談吧。下面還有一些小建議。

1.若是想要爬取的質量更高,儘可能使用寬度優先的策略,在配置裏設置 SCHEDULER_ORDER = ‘BFO’

2.修改單爬蟲的最大並行請求數 CONCURRENT_REQUESTS_PER_SPIDER

3.修改twisted的線程池大小,默認值是10。參考(Using Threads in Twisted)

在scrapy/core/manage.py爬蟲啓動前加上

reactor.suggestThreadPoolSize(poolsize)

4.能夠開啓dns cache來提升性能

在配置裏面加上 EXTENSIONS={’scrapy.contrib.resolver.CachingResolver’: 0,}

5.若是本身實現duplicate filter的話注意要保證它是一直可用的,dupfilter裏的異常是不會出如今日誌文件中的,好像外面作了try-expect處理,我也沒仔細看這部分

這是接着以前的()寫的,上一篇裏主要是寫了一些解決性能問題的思路。時間過去快半年了,咱們抓取的頁面也不止百萬了。咱們在爬蟲上也作了一些小改進,好比改善了連接提取器,(一)裏提到的四個問題也都有不一樣程度的改進,可是仍是有一些問題遲遲沒能解決。

scrapy的問題

爬蟲是一個很依賴於網絡io的應用,單機的處理能力有限,很快就變成瓶頸。而scrapy並非一個分佈式的設計,在須要大規模爬取的狀況下就很成問題。固然能夠經過修改Request隊列來實現分佈式爬取,並且工做量也不算特別大。

scrapy的並行度不高。力圖在爬蟲裏作一些計算性的操做就會影響抓取的速率。這主要是python裏的線程機制形成的,由於Python使用了GIL(和Ruby同樣),多線程並不會帶來太多速度上的提高(除非用Python的C擴展實現本身的模塊,這樣繞過了GIL)。Summary:Use Python threads if you need to run IO operations in parallel. Do not if you need to run computations in parallel.

scrapy的內存消耗很快。多是出於性能方面的考慮,pending requests並非序列化存儲在硬盤中,而是放在內存中的(畢竟IO很費時),並且全部Request都放在內存中。你抓取到 百萬網頁的時候,考慮到單個網頁時產生不少連接的,pending request極可能就近千萬了,加上腳本語言裏的對象原本就有額外成本,再考慮到GC不會當即釋放內存,內存佔用就至關可觀了。這個問題對咱們的應用倒也沒形成多大困擾,找臺二三十G內存的機器就能知足很長時間的需求。

memory應該是腳本語言的硬傷,單機程序來講就更受限了。我記得豆瓣的網站就是用python寫的,框架好像用得就是quixote。Davies說內存超過必定量就由master kill掉,再從新fork。持續運行的python程序消耗內存很快,內存泄露也很難調試。

歸根到底,這兩個問題是根植於語言之中的。

關於如何修改scrapy

前些日子跟幾個作爬蟲的朋友在五道口交流了一些scrapy的使用經驗。談點建議吧,若是你想修改scrapy適應本身的需求的話,能夠先看看文檔,可否經過修改配置解決(好比寬度優先/深度優先,限制爬取深度這些均可以經過修改配置解決的)。再contrib和contrib_exp兩個目錄下有沒有實現好的模塊,而後再去scrapy snippets看看。若是都不能解決,就去scrapy的google group裏問一下,有些實現了的模塊並未寫在文檔中,好比DNS Cache。真的須要本身動手實現了,再查scrapy的在線文檔,寫的仍是挺詳細的,關於架構和一些關鍵的數據結構以及一些經常使用設置都有說明,有搜索功能(sphinx生成的)。

列舉scrapy的google group裏常常有人提出的一些需求:

javascript爬取/ajax爬取(跟js的複雜程度正相關,對於複雜的js通用的解決方案應該就是內置js執行引擎)
讓爬蟲運行在單獨線程(see 「Run scrapy crawler in a thread「,考慮到Python的多線程機制,這樣不太可能有多大的性能提高)
同時運行多個爬蟲(新版的scrapy自己就支持這一特性)
防止被網站封禁(不影響人家服務器正常工做是你的義務…本身控制下爬取速率吧)
把Request存儲到disk或者database上(pluskid同窗講過)

P.S. 推薦

搜索引擎:原理、技術與系統

很是好的關於搜索引擎的書,基本原理講解得全面,也涉及到足夠多的細節。相對市面上介紹nutch的書籍而言,它對基本原理的講解更細節,對本身動手實現一個簡單的搜索引擎更 有幫助。好比它會講如何提取連接,如何對網頁消重,甚至講了一個簡單的中文最大正向匹配分詞算法。也像douban裏的評論裏所說,閱讀它須要點IR 方面的基礎,有些知識它以爲理所固然就一筆帶過了。仍是有國內教材的做風,重在羅列,不以讀者理解爲目的。一些很差理解的地方沒有作過多闡述。P.S. 我以爲nutch裏的爬蟲原本就實現得很粗糙。

做者:leoking01 發表於2014-11-12 11:50:02 原文連接
閱讀:3 評論:0 查看評論
相關文章
相關標籤/搜索