天天看點

一看就明白的爬蟲入門講解:基礎理論篇

我們的目的是什麼

内容從何而來

了解網絡請求

一些常見的限制方式

嘗試解決問題的思路

效率問題的取舍

一般來講對我們而言,需要抓取的是某個網站或者某個應用的内容,提取有用的價值,内容一般分為兩部分,非結構化的文本,或結構化的文本。

HTML文本基本上是傳統爬蟲過程中最常見的,也就是大多數時候會遇到的情況,例如抓取一個網頁,得到的是HTML,然後需要解析一些常見的元素,提取一些關鍵的資訊。HTML其實理應屬于結構化的文本組織,但是又因為一般我們需要的關鍵資訊并非直接可以得到,需要進行對HTML的解析查找,甚至一些字元串操作才能得到,是以還是歸類于非結構化的資料進行中。

常見解析方式如下:

CSS選擇器

現在的網頁樣式比較多,是以一般的網頁都會有一些CSS的定位,例如class,id等等,或者我們根據常見的節點路徑進行定位,例如騰訊首頁的财經部分。

這裡id就為finance,我們用css選擇器,就是"#finance"就得到了财經這一塊區域的html,同理,可以根據特定的css選擇器可以擷取其他的内容。

XPATH

XPATH是一種頁面元素的路徑選擇方法,利用Chrome可以快速得到,如:

copy XPATH 就能得到——//*[@id="finance"]

正規表達式

正規表達式,用标準正則解析,一般會把HTML當做普通文本,用指定格式比對當相關文本,适合小片段文本,或者某一串字元,或者HTML包含javascript的代碼,無法用CSS選擇器或者XPATH。

字元串分隔

同正規表達式,更為偷懶的方法,不建議使用。

例如一篇文章,或者一句話,我們的初衷是提取有效資訊,是以如果是滞後處理,可以直接存儲,如果是需要實時提取有用資訊,常見的處理方式如下:

分詞

根據抓取的網站類型,使用不同詞庫,進行基本的分詞,然後變成詞頻統計,類似于向量的表示,詞為方向,詞頻為長度。

NLP

自然語言處理,進行語義分析,用結果表示,例如正負面等。

結構化的資料是最好處理,一般都是類似JSON格式的字元串,直接解析JSON資料就可以了,提取JSON的關鍵字段即可。

過去我們常需要擷取的内容主要來源于網頁,一般來講,我們決定進行抓取的時候,都是網頁上可看到的内容,但是随着這幾年移動網際網路的發展,我們也發現越來越多的内容會來源于移動App,是以爬蟲就不止局限于一定要抓取解析網頁,還有就是模拟移動app的網絡請求進行抓取,是以這一部分我會分兩部分進行說明。

網頁内容一般就是指我們最終在網頁上看到的内容,但是這個過程其實并不是網頁的代碼裡面直接包含内容這麼簡單,是以對于很多新人而言,會遇到很多問題,比如:

明明在頁面用Chrome或者Firefox進行審查元素時能看到某個HTML标簽下包含内容,但是抓取的時候為空。 很多内容一定要在頁面上點選某個按鈕或者進行某個互動操作才能顯示出來。

是以對于很多新人的做法是用某個語言别人模拟浏覽器操作的庫,其實就是調用本地浏覽器或者是包含了一些執行JavaScript的引擎來進行模拟操作抓取資料,但是這種做法顯然對于想要大量抓取資料的情況下是效率非常低下,并且對于技術人員本身而言也相當于在用一個盒子,那麼對于這些内容到底是怎麼顯示在網頁上的呢?主要分為以下幾種情況:

網頁包含内容

這種情況是最容易解決的,一般來講基本上是靜态網頁已經寫死的内容,或者動态網頁,采用模闆渲染,浏覽器擷取到HTML的時候已經是包含所有的關鍵資訊,是以直接在網頁上看到的内容都可以通過特定的HTML标簽得到。

JavaScript代碼加載内容

這種情況是由于雖然網頁顯示時,内容在HTML标簽裡面,但是其實是由于執行js代碼加到标簽裡面的,是以這個時候内容在js代碼裡面的,而js的執行是在浏覽器端的操作,是以用程式去請求網頁位址的時候,得到的response是網頁代碼和js的代碼,是以自己在浏覽器端能看到内容,解析時由于js未執行,肯定找到指定HTML标簽下内容肯定為空,這個時候的處理辦法,一般來講主要是要找到包含内容的js代碼串,然後通過正規表達式獲得相應的内容,而不是解析HTML标簽。

Ajax異步請求

這種情況是現在很常見的,尤其是在内容以分頁形式顯示在網頁上,并且頁面無重新整理,或者是對網頁進行某個互動操作後,得到内容。那我們該如何分析這些請求呢?這裡我以Chrome的操作為例,進行說明:

是以當我們開始重新整理頁面的時候就要開始跟蹤所有的請求,觀察資料到底是在哪一步加載進來的。然後當我們找到核心的異步請求的時候,就隻用抓取這個異步請求就可以了,如果原始網頁沒有任何有用資訊,也沒必要去抓取原始網頁了。

因為現在移動應用越來越多,很多有用資訊都在App裡面,另外解析非結構化文本和結構文本對比而言,結構化文本會簡單多了,不同去找内容,去過多分析解析,所有既有網站又有App的話,推薦抓取App,大多數情況下基本上隻是一些JSON資料的API了。

那麼App的資料該如何抓取呢?通用的方法就是抓包,基本的做法就是電腦安裝抓包軟體,配置好端口,然後記下ip,手機端和電腦在同一個區域網路裡面,然後在手機的網絡連接配接裡面設定好代理,這個時候打開App進行一些操作,如果有網絡資料請求,則都會被抓包軟體記下,就如上Chrome分析網絡請求一樣,你可以看到所有的請求情況,可以模拟請求操作。這裡Mac上我推薦軟體Charles,Windows推薦Fiddler2。

具體如何使用,之後我再做詳述,可能會涉及到HTTPS證書的問題。

剛剛一直在寬泛的提到一些我們需要找到請求,進行請求,對于請求隻是一筆帶過,但請求是很重要的一部分,包括如何繞過限制,如何發送正确地資料,都需要對的請求,這裡就要詳細的展開說下請求,以及如何模拟請求。

我們常說爬蟲其實就是一堆的HTTP請求,找到待爬取的連結,不管是網頁連結還是App抓包得到的API連結,然後發送一個請求包,得到一個傳回包(也有HTTP長連接配接,或者Streaming的情況,這裡不考慮),是以核心的幾個要素就是:

URL

請求方法(POST, GET)

請求包headers

請求包内容

傳回包headers

在用Chrome進行網絡請求捕獲或者用抓包工具分析請求時,最重要的是弄清楚URL,請求方法,然後headers裡面的字段,大多數出問題就出在headers裡面,最常限制的幾個字段就是User-Agent, Referer, Cookie 另外Base Auth也是在headers裡面加了Autheration的字段。

請求内容也就是post時需要發送的資料,一般都是将Key-Value進行urlencode。傳回包headers大多數會被人忽視,可能隻得到内容就可以了,但是其實很多時候,很多人會發現明明url,請求方法還有請求包的内容都對了,為什麼沒有傳回内容,或者發現請求被限制,其實這裡大概有兩個原因:

一個是傳回包的内容是空的,但是在傳回包的headers的字段裡面有個Location,這個Location字段就是告訴浏覽器重定向,是以有時候代碼沒有自動跟蹤,自然就沒有内容了; 另外一個就是很多人會頭疼的Cookie問題,簡單說就是浏覽器為什麼知道你的請求合法的,例如已登入等等,其實就是可能你之前某個請求的傳回包的headers裡面有個字段叫Set-Cookie,Cookie存在本地,一旦設定後,除非過期,一般都會自動加在請求字段上,是以Set-Cookie裡面的内容就會告訴浏覽器存多久,存的是什麼内容,在哪個路徑下有用,Cookie都是在指定域下,一般都不跨域,域就是你請求的連結host。

是以分析請求時,一定要注意前四個,在模拟時保持一緻,同時觀察第五個傳回時是不是有限制或者有重定向。

上述都是講的都是一些的基礎的知識,現在我就列一些比較常見的限制方式,如何突破這些限制抓取資料。

Basic Auth

一般會有使用者授權的限制,會在headers的Autheration字段裡要求加入;

Referer

通常是在通路連結時,必須要帶上Referer字段,伺服器會進行驗證,例如抓取京東的評論;

User-Agent

會要求真是的裝置,如果不加會用程式設計語言包裡自有User-Agent,可以被辨識出來;

Cookie

一般在使用者登入或者某些操作後,服務端會在傳回包中包含Cookie資訊要求浏覽器設定Cookie,沒有Cookie會很容易被辨識出來是僞造請求;

也有本地通過JS,根據服務端傳回的某個資訊進行處理生成的加密資訊,設定在Cookie裡面;

Gzip

請求headers裡面帶了gzip,傳回有時候會是gzip壓縮,需要解壓;

JavaScript加密操作

一般都是在請求的資料包内容裡面會包含一些被javascript進行加密限制的資訊,例如新浪微網誌會進行SHA1和RSA加密,之前是兩次SHA1加密,然後發送的密碼和使用者名都會被加密;

其他字段

因為http的headers可以自定義地段,是以第三方可能會加入了一些自定義的字段名稱或者字段值,這也是需要注意的。

真實的請求過程中,其實不止上面某一種限制,可能是幾種限制組合在一次,比如如果是類似RSA加密的話,可能先請求伺服器得到Cookie,然後再帶着Cookie去請求伺服器拿到公鑰,然後再用js進行加密,再發送資料到伺服器。是以弄清楚這其中的原理,并且耐心分析很重要。

首先大的地方,加入我們想抓取某個資料源,我們要知道大概有哪些路徑可以擷取到資料源,基本上無外乎三種:

PC端網站;

針對移動裝置響應式設計的網站(也就是很多人說的H5, 雖然不一定是H5);

移動App;

原則是能抓移動App的,最好抓移動App,如果有針對移動裝置優化的網站,就抓針對移動裝置優化的網站,最後考慮PC網站。因為移動App基本都是API很簡單,而移動裝置通路優化的網站一般來講都是結構簡單清晰的HTML,而PC網站自然是最複雜的了;

針對PC端網站和移動網站的做法一樣,分析思路可以一起講,移動App單獨分析。

首先是網站類的,使用的工具就是Chrome,建議用Chrome的隐身模式,分析時不用頻繁清楚cookie,直接關閉視窗就可以了。

具體操作步驟如下:

輸入網址後,先不要回車确認,右鍵選擇審查元素,然後點選網絡,記得要勾上preserve log選項,因為如果出現上面提到過的重定向跳轉,之前的請求全部都會被清掉,影響分析,尤其是重定向時還加上了Cookie;

接下來觀察網絡請求清單,資源檔案,例如css,圖檔基本都可以忽略,第一個請求肯定就是該連結的内容本身,是以檢視源碼,确認頁面上需要抓取的内容是不是在HTML标簽裡面,很簡單的方法,找到自己要找的内容,看到父節點,然後再看源代碼裡面該父節點裡面有沒有内容,如果沒有,那麼一定是異步請求,如果是非異步請求,直接抓該連結就可以了。

分析異步請求,按照網絡清單,略過資源檔案,然後點選各個請求,觀察是否在傳回時包含想要的内容,有幾個方法:

内容比較有特點,例如人的屬性資訊,物品的價格,或者微網誌清單等内容,直接觀察可以判斷是不是該異步請求;

知道異步加載的内容節點或者父節點的class或者id的名稱,找到js代碼,閱讀代碼得到異步請求;

确認異步請求之後,就是要分析異步請求了,簡單的,直接請求異步請求,能得到資料,但是有時候異步請求會有限制,是以現在分析限制從何而來。

針對分析對請求的限制,思路是逆序方法。

先找到最後一個得到内容的請求,然後觀察headers,先看post資料或者url的某個參數是不是都是已知資料,或者有意義資料,如果發現不确定的先帶上,隻是更改某個關鍵字段,例如page,count看結果是不是會正常,如果不正常,比如多了個token,或者某個字段明顯被加密,例如使用者名密碼,那麼接下來就要看JS的代碼,看到底是哪個函數進行了加密,一般會是原生JS代碼加密,那麼看到代碼,直接加密就行,如果是類似RSA加密,那麼就要看公鑰是從何而來,如果是請求得到的,那麼就要往上分析請求,另外如果是發現請求headers裡面有陌生字段,或者有Cookie也要往上看請求,Cookie在哪一步設定的;

接下來找到剛剛那個請求未知來源的資訊,例如Cookie或者某個加密需要的公鑰等等,看看上面某個請求是不是已經包含,依次類推。

然後是App類的,使用的工具是Charles,手機和電腦在一個區域網路内,先用Charles配置好端口,然後手機設定代理,ip為電腦的ip,端口為設定的端口,然後如果手機上請求網絡内容時,Charles會顯示相應地請求,那麼就ok了,分析的大體邏輯基本一緻,限制會相對少很多,但是也有幾種情況需要注意:

加密,App有時候也有一些加密的字段,這個時候,一般來講都會進行反編譯進行分析,找到對應的代碼片段,逆推出加密方法;

gzip壓縮或者base64編碼,base64編碼的辨識度較高,有時候資料被gzip壓縮了,不過Charles都是有自動解密的;

https證書,有的https請求會驗證證書,Charles提供了證書,可以在官網找到,手機通路,然後信任添加就可以。

一般來講在抓取大量資料,例如全網抓取京東的評論,微網誌所有人的資訊,微網誌資訊,關注關系等等,這種上十億到百億次設定千億次的請求必須考慮效率,否者一天隻有86400秒,那麼一秒鐘要抓100次,一天也才864w次請求,也需要100多天才能到達十億級别的請求量。

涉及到大規模的抓取,一定要有良好的爬蟲設計,一般很多開源的爬蟲架構也都是有限制的,因為中間涉及到很多其他的問題,例如資料結構,重複抓取過濾的問題,當然最重要的是要把帶寬利用滿,是以分布式抓取很重要,接下來我會有一篇專門講分布式的爬蟲設計,分布式最重要的就是中間消息通信,如果想要抓的越多越快,那麼對中間的消息系統的吞吐量要求也越高。

但是對于一些不太大規模的抓取就沒要用分布式的一套,比較消耗時間,基本隻要保證單機器的帶寬能夠利用滿就沒問題,是以做好并發就可以,另外對于資料結構也要有一定的控制,很多人寫程式,記憶體越寫越大,抓取越來越慢,可能存在的原因就包括,一個是用了記憶體存一些資料沒有進行釋放,第二個可能有一些hashset的判斷,最後判斷的效率越來越低,比如用bloomfilter替換就會優化很多。

本文轉自 yntmdr 51CTO部落格,原文連結:http://blog.51cto.com/yntmdr/1901928,如需轉載請自行聯系原作者

繼續閱讀