scrapy定製爬蟲-爬取javascript內容

pythontab發表於2014-03-11

很多網站都使用javascript...網頁內容由js動態生成,一些js事件觸發的頁面內容變化,連結開啟.甚至有些網站在沒有js的情況下根本不工作,取而代之返回你一條類似"請開啟瀏覽器js"之類的內容.

對javascript的支援有四種解決方案:
1,寫程式碼模擬相關js邏輯.
2,呼叫一個有介面的瀏覽器,類似各種廣泛用於測試的,selenium這類.
3,使用一個無介面的瀏覽器,各種基於webkit的,casperjs,phantomjs等等.
4,結合一個js執行引擎,自己實現一個輕量級的瀏覽器.難度很大.

對於簡單的有限爬取任務,若可以透過程式碼模擬js邏輯,首選這種方案,例如,在duckduckgo搜尋引擎中,翻頁這個動作是靠js觸發的.模擬似乎還是很難,然後我注意到他頁面的第二個form,似乎submit後就可以翻頁,試了一下果然如此.
在寫程式碼模擬相關js邏輯時,首先試下關閉瀏覽器的js,看下是否能獲取到需要的東西.有些頁面提供了沒有js的相容.不行再開chrome的控制檯或firebug觀察js邏輯,可能是ajax這類收發包.用urllib2(推薦requests庫)模擬即可,也可能是修改dom之類,用lxml這類對應修改即可.說來就是js執行了什麼,就用python程式碼對應模擬執行.

也可選擇使用selenium這類,缺點是效率很低,你應當先測試一下selenium啟動一個瀏覽器例項所需時間你是否可接受.這個時間一般在秒級別.再考慮到瀏覽器開啟頁面渲染,就更慢了.在效率可接受的前提下,這個方案也不錯.
這個方案的另一個問題是在沒有桌面環境的伺服器上,selenium目測無法執行.

對規模不小,模擬js不可行,selenium效率太低,或需要在無桌面環境上執行的情況.有無介面瀏覽器,幾個無介面瀏覽器大體情況如下:
1,casperjs,phantomjs:非py,可以透過命令列呼叫,功能基本滿足,推薦先看下這兩個是否滿足.比較成熟.phantomjs還有一個非官方的webdriver協議實現,由此可透過selenium調phantomjs實現無介面.
2,ghost,spynner等:py定製的webkit,個人覺得spynner程式碼亂,ghost程式碼質量不錯.但有bug.我看過幾個這類庫後自己改了一個.
這種方案的詳細情況見下面.

最後還有一種選擇,在js執行引擎的基礎上,自己實現一個輕量級的支援js的無介面瀏覽器.除非你有非常非常非常多需要爬取的內容,效率十分十分十分重要.若你有這個想法,可以看下pyv8,在v8的示例程式碼中有一個基於v8實現的簡易瀏覽器模型.是的,只是個模型,並不完全可用,你要自己填充裡面的一些方法.實現這些你需要在js引擎(v8),http庫(urllib2)之上實現這些功能,1,當網頁開啟時獲取其包含的js程式碼,2,構建一個瀏覽器模型,包括各種事件與dom樹.3,執行js.除此之外可能還有其他一些細節.難度較大.
網上可以找到一淘所用購物比價爬蟲的一篇相關ppt.該爬蟲也僅使用的第三種方案.可以看下這篇ppt.該爬蟲大概是用的webkit,scrapy,另外把scrapy的排程佇列改為基於redis的,實現分散式.

如何實現:

回頭談點背景知識,scrapy使用了twisted.一個非同步網路框架.因此要留意潛在的阻塞情況.但注意到settings中有個引數是設定ItemPipeline的並行度.由此推測pipeline不會阻塞,pipeline可能是線上程池中執行的(未驗證).Pipeline一般用於將抓取到的資訊儲存(寫資料庫,寫檔案),因此這裡你就不用擔心耗時操作會阻塞整個框架了,也就不用在Pipeline中將這個寫操作實現為非同步.
除此之外框架的其他部分.都是非同步的,簡單說來就是,爬蟲生成的請求交由排程器去下載,然後爬蟲繼續執行.排程器完成下載後會將響應交由爬蟲解析.

網上找到的參考例子,部分將js支援寫到了DownloaderMiddleware中,scrapy官網的code snippet也是這樣 .若這樣實現,就阻塞了整個框架,爬蟲的工作模式變成了,下載-解析-下載-解析,而不在是並行的下載.在對效率要求不高的小規模爬取中問題不大.
更好的做法是將js支援寫到scrapy的downloader裡.網上有一個這樣的實現(使用selenium+phantomjs).不過僅支援get請求.

在適配一個webkit給scrapy的downloader時,有各種細節需要處理.


相關文章