抓取前端渲染的頁面
在抓取階段,在爬蟲中內建乙個瀏覽器核心,執行js渲染頁面後,再抓取。這方面對應的工具有selenium、htmlunit或者phantomjs。但是這些工具都存在一定的效率問題,同時也不是那麼穩定。好處是編寫規則同靜態頁面一樣。
因為js渲染頁面的資料也是從後端拿到,而且基本上都是ajax獲取,所以分析ajax請求,找到對應資料的請求,也是比較可行的做法。而且相對於頁面樣式,這種介面變化可能性更小。缺點就是找到這個請求,並進行模擬,是乙個相對困難的過程,也需要相對多的分析經驗。
對比兩種方式,我的觀點是,對於一次性或者小規模的需求,用第一種方式省時省力。但是對於長期性的、大規模的需求,還是第二種會更靠譜一些。對於一些站點,甚至還有一些js混淆的技術,這個時候,第一種的方式基本是萬能的,而第二種就會很複雜了。
這裡我主要介紹第二種方法,希望到最後你會發現:原來解析乙個前端渲染的頁面,也沒有那麼複雜。這裡我們以angularjs中文社群為例。
1 如何判斷前端渲染
判斷頁面是否為js渲染的方式比較簡單,在瀏覽器中直接檢視原始碼(windows下ctrl+u,mac下command+alt+u),如果找不到有效的資訊,則基本可以肯定為js渲染。
這個例子中,在頁面中的標題「有孚計算機網路-前端攻城師」在原始碼中無法找到,則可以斷定是js渲染,並且這個資料是ajax得到。
2 分析請求
下面我們進入最難的一部分:找到這個資料請求。這一步能幫助我們的工具,主要是瀏覽器中檢視網路請求的開發者工具。
以chome為例,我們開啟「開發者工具」(windows下是f12,mac下是command+alt+i),然後重新重新整理頁面(也有可能是下拉頁面,總之是所有你認為可能觸發新資料的操作),然後記得保留現場,把請求乙個個拿來分析吧!
這一步需要一點耐心,但是也並不是無章可循。首先能幫助我們的是上方的分類篩選(all、document等選項)。如果是正常的ajax,在xhr標籤下會顯示,而jsonp請求會在scripts標籤下,這是兩個比較常見的資料型別。
然後你可以根據資料大小來判斷一下,一般結果體積較大的更有可能是返回資料的介面。剩下的,基本靠經驗了,例如這裡這個"latest?p=1&s=20"一看就很可疑…
對於可疑的位址,這時候可以看一下響應體是什麼內容了。這裡在開發者工具看不清楚,我們把urlapi/article/latest?p=1&s=20複製到位址列,重新請求一次(如果用chrome推薦裝個jsonviewer,檢視ajax結果很方便)。檢視結果,看來我們找到了想要的。
同樣的辦法,我們進入到帖子詳情頁,找到了具體內容的請求:api/article/a0y2。
3 編寫程式
回想一下之前列表+目標頁的例子,會發現我們這次的需求,跟之前是類似的,只不過換成了ajax方式-ajax方式的列表,ajax方式的資料,而返回資料變成了json。那麼,我們仍然可以用上次的方式,分為兩種頁面來進行編寫:
資料列表
在這個列表頁,我們需要找到有效的資訊,來幫助我們構建目標ajax的url。這裡我們看到,這個_id應該就是我們想要的帖子的id,而帖子的詳情請求,就是由一些固定url加上這個id組成。所以在這一步,我們自己手動構造url,並加入到待抓取佇列中。這裡我們使用jsonpath這種選擇語言來選擇資料(webmagic-extension包中提供了jsonpathselector來支援它)。
if (page.geturl().regex(list_url).match()) {
//這裡我們使用jsonpath這種選擇語言來選擇資料
list ids = new jsonpathselector("$.data[*]._id").selectlist(page.getrawtext());
if (collectionutils.isnotempty(ids)) {
for (string id : ids) {
page.addtargetrequest("api/article/"+id);
目標資料
有了url,實際上解析目標資料就非常簡單了,因為json資料是完全結構化的,所以省去了我們分析頁面,編寫xpath的過程。這裡我們依然使用jsonpath來獲取標題和內容。
page.putfield("title", new jsonpathselector("$.data.title").select(page.getrawtext()));
page.putfield("content", new jsonpathselector("$.data.content").select(page.getrawtext()));
4 總結
後端渲染的頁面
前端渲染的頁面
對於不同的站點,這個輔助資料可能是在頁面html中已經預先輸出,也可能是通過ajax去請求,甚至可能是多次資料請求的過程,但是這個模式基本是固定的。
但是這些資料請求的分析比起頁面分析來說,仍然是要複雜得多,所以這其實是動態頁面抓取的難點。
ps:webmagic 0.5.0之後會將json的支援增加到鏈式api中,以後你可以使用:
page.getjson().jsonpath("$.name").get();
這樣的方式來解析ajax請求了。
同時也支援
page.getjson().removepadding("callback").jsonpath("$.name").get();
這樣的方式來解析jsonp請求。
WebMagic實現分布式抓取以及斷點抓取
從去年到今年,筆者主要負責的是與合作方的內容對接,新增的合作商不是很多的情況下,在我自從去年引入了 webmagic 這個爬蟲框架之後,基本很少需要去關注維護爬蟲,做的最多的是新接入合作商去寫對應爬蟲抓取模板。因為在 中實現了增量抓取,單機也足以承擔日常的抓取工作。在前兩周,由於公司拓展新的業務渠道...
抓取貓眼電影前100
import json import requests import re import time from requests.exceptions import requestexception def get one page url try headers response requests....
golang爬蟲colly 抓取豆瓣前250電影
工作中要用到一點爬蟲相關的,以前都是用python寫的,最近研究golang 主要是工作中一些api需要用golang 才在研究,後續研究完了有可能寫個整的文章,這次用colly爬去豆瓣電影 top250 好像所有爬蟲入門都是用這個 感謝豆瓣 簡單記錄 如下,主要使用了colly和goquery f...