爬蟲經驗總結

關於爬蟲內容的分享,我會分紅兩篇,六個部分來分享,分別是:javascript

 

  1. 咱們的目的是什麼
  2. 內容從何而來
  3. 瞭解網絡請求
  4. 一些常見的限制方式
  5. 嘗試解決問題的思路
  6. 效率問題的取捨

 

1、咱們的目的是什麼

通常來說對咱們而言,須要抓取的是某個網站或者某個應用的內容,提取有用的價值,內容通常分爲兩部分,非結構化的文本,或結構化的文本。css

1. 關於非結構化的數據

1.1 HTML文本(包含JavaScript代碼)

HTML文本基本上是傳統爬蟲過程當中最多見的,也就是大多數時候會遇到的狀況,例如抓取一個網頁,獲得的是HTML,而後須要解析一些常見的元素,提取一些關鍵的信息。HTML其實理應屬於結構化的文本組織,可是又由於通常咱們須要的關鍵信息並不是直接能夠獲得,須要進行對HTML的解析查找,甚至一些字符串操做才能獲得,因此仍是歸類於非結構化的數據處理中。html

常看法析方式以下:java

 

  • CSS選擇器

 

如今的網頁樣式比較多,因此通常的網頁都會有一些CSS的定位,例如class,id等等,或者咱們根據常見的節點路徑進行定位,例如騰訊首頁的財經部分。正則表達式

這裏id就爲finance,咱們用css選擇器,就是"#finance"就獲得了財經這一塊區域的html,同理,能夠根據特定的css選擇器能夠獲取其餘的內容。編程

 

  • XPATH

 

XPATH是一種頁面元素的路徑選擇方法,利用Chrome能夠快速獲得,如:跨域

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

 

  • 正則表達式

 

正則表達式,用標準正則解析,通常會把HTML當作普通文本,用指定格式匹配當相關文本,適合小片斷文本,或者某一串字符,或者HTML包含javascript的代碼,沒法用CSS選擇器或者XPATH。瀏覽器

 

  • 字符串分隔

 

同正則表達式,更爲偷懶的方法,不建議使用。服務器

1.2 一段文本

例如一篇文章,或者一句話,咱們的初衷是提取有效信息,因此若是是滯後處理,能夠直接存儲,若是是須要實時提取有用信息,常見的處理方式以下:cookie

 

  • 分詞

 

根據抓取的網站類型,使用不一樣詞庫,進行基本的分詞,而後變成詞頻統計,相似於向量的表示,詞爲方向,詞頻爲長度。

 

  • NLP

 

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

2. 關於結構化的數據

結構化的數據是最好處理,通常都是相似JSON格式的字符串,直接解析JSON數據就能夠了,提取JSON的關鍵字段便可。

2、內容從何而來

過去咱們常須要獲取的內容主要來源於網頁,通常來說,咱們決定進行抓取的時候,都是網頁上可看到的內容,可是隨着這幾年移動互聯網的發展,咱們也發現愈來愈多的內容會來源於移動App,因此爬蟲就不止侷限於必定要抓取解析網頁,還有就是模擬移動app的網絡請求進行抓取,因此這一部分我會分兩部分進行說明。

1 網頁內容

網頁內容通常就是指咱們最終在網頁上看到的內容,可是這個過程其實並非網頁的代碼裏面直接包含內容這麼簡單,因此對於不少新人而言,會遇到不少問題,好比:

明明在頁面用Chrome或者Firefox進行審查元素時能看到某個HTML標籤下包含內容,可是抓取的時候爲空。
不少內容必定要在頁面上點擊某個按鈕或者進行某個交互操做才能顯示出來。

因此對於不少新人的作法是用某個語言別人模擬瀏覽器操做的庫,其實就是調用本地瀏覽器或者是包含了一些執行JavaScript的引擎來進行模擬操做抓取數據,可是這種作法顯然對於想要大量抓取數據的狀況下是效率很是低下,而且對於技術人員自己而言也至關於在用一個盒子,那麼對於這些內容究竟是怎麼顯示在網頁上的呢?主要分爲如下幾種狀況:

 

  • 網頁包含內容

 

這種狀況是最容易解決的,通常來說基本上是靜態網頁已經寫死的內容,或者動態網頁,採用模板渲染,瀏覽器獲取到HTML的時候已是包含全部的關鍵信息,因此直接在網頁上看到的內容均可以經過特定的HTML標籤獲得。

 

  • JavaScript代碼加載內容

 

這種狀況是因爲雖然網頁顯示時,內容在HTML標籤裏面,可是實際上是因爲執行js代碼加到標籤裏面的,因此這個時候內容在js代碼裏面的,而js的執行是在瀏覽器端的操做,因此用程序去請求網頁地址的時候,獲得的response是網頁代碼和js的代碼,因此本身在瀏覽器端能看到內容,解析時因爲js未執行,確定找到指定HTML標籤下內容確定爲空,這個時候的處理辦法,通常來說主要是要找到包含內容的js代碼串,而後經過正則表達式得到相應的內容,而不是解析HTML標籤。

 

  • Ajax異步請求

 

這種狀況是如今很常見的,尤爲是在內容以分頁形式顯示在網頁上,而且頁面無刷新,或者是對網頁進行某個交互操做後,獲得內容。那咱們該如何分析這些請求呢?這裏我以Chrome的操做爲例,進行說明:

因此當咱們開始刷新頁面的時候就要開始跟蹤全部的請求,觀察數據究竟是在哪一步加載進來的。而後當咱們找到核心的異步請求的時候,就只用抓取這個異步請求就能夠了,若是原始網頁沒有任何有用信息,也不必去抓取原始網頁了。

2 App內容

由於如今移動應用愈來愈多,不少有用信息都在App裏面,另外解析非結構化文本和結構文本對比而言,結構化文本會簡單多了,不一樣去找內容,去過多分析解析,全部既有網站又有App的話,推薦抓取App,大多數狀況下基本上只是一些JSON數據的API了

那麼App的數據該如何抓取呢?通用的方法就是抓包,基本的作法就是電腦安裝抓包軟件,配置好端口,而後記下ip,手機端和電腦在同一個局域網裏面,而後在手機的網絡鏈接裏面設置好代理,這個時候打開App進行一些操做,若是有網絡數據請求,則都會被抓包軟件記下,就如上Chrome分析網絡請求同樣,你能夠看到全部的請求狀況,能夠模擬請求操做。這裏Mac上我推薦軟件Charles,Windows推薦Fiddler2。

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

3、瞭解網絡請求

剛剛一直在寬泛的提到一些咱們須要找到請求,進行請求,對於請求只是一筆帶過,但請求是很重要的一部分,包括如何繞過限制,如何發送正確地數據,都須要對的請求,這裏就要詳細的展開說下請求,以及如何模擬請求。

咱們常說爬蟲其實就是一堆的HTTP請求,找到待爬取的連接,無論是網頁連接仍是App抓包獲得的API連接,而後發送一個請求包,獲得一個返回包(也有HTTP長鏈接,或者Streaming的狀況,這裏不考慮),因此核心的幾個要素就是:

 

  1. URL
  2. 請求方法(POST, GET)
  3. 請求包headers
  4. 請求包內容
  5. 返回包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。

因此分析請求時,必定要注意前四個,在模擬時保持一致,同時觀察第五個返回時是否是有限制或者有重定向。

4、一些常見的限制方式

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

 

  • 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進行加密,再發送數據到服務器。因此弄清楚這其中的原理,而且耐心分析很重要。

5、嘗試解決問題的思路

首先大的地方,加入咱們想抓取某個數據源,咱們要知道大概有哪些路徑能夠獲取到數據源,基本上無外乎三種:

 

  1. PC端網站;
  2. 針對移動設備響應式設計的網站(也就是不少人說的H5, 雖然不必定是H5);
  3. 移動App;

 

原則是能抓移動App的,最好抓移動App,若是有針對移動設備優化的網站,就抓針對移動設備優化的網站,最後考慮PC網站。由於移動App基本都是API很簡單,而移動設備訪問優化的網站通常來說都是結構簡單清晰的HTML,而PC網站天然是最複雜的了;

針對PC端網站和移動網站的作法同樣,分析思路能夠一塊兒講,移動App單獨分析。

1 網站類型的分析

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

具體操做步驟以下:

 

  • 輸入網址後,先不要回車確認,右鍵選擇審查元素,而後點擊網絡,記得要勾上preserve log選項,由於若是出現上面提到過的重定向跳轉,以前的請求所有都會被清掉,影響分析,尤爲是重定向時還加上了Cookie;
  • 接下來觀察網絡請求列表,資源文件,例如css,圖片基本均可以忽略,第一個請求確定就是該連接的內容自己,因此查看源碼,確認頁面上須要抓取的內容是否是在HTML標籤裏面,很簡單的方法,找到本身要找的內容,看到父節點,而後再看源代碼裏面該父節點裏面有沒有內容,若是沒有,那麼必定是異步請求,若是是非異步請求,直接抓該連接就能夠了。

 

分析異步請求,按照網絡列表,略過資源文件,而後點擊各個請求,觀察是否在返回時包含想要的內容,有幾個方法:

 

  • 內容比較有特色,例如人的屬性信息,物品的價格,或者微博列表等內容,直接觀察能夠判斷是否是該異步請求;
  • 知道異步加載的內容節點或者父節點的class或者id的名稱,找到js代碼,閱讀代碼獲得異步請求;
  • 確認異步請求以後,就是要分析異步請求了,簡單的,直接請求異步請求,能獲得數據,可是有時候異步請求會有限制,因此如今分析限制從何而來。

 

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

 

  • 先找到最後一個獲得內容的請求,而後觀察headers,先看post數據或者url的某個參數是否是都是已知數據,或者有意義數據,若是發現不肯定的先帶上,只是更改某個關鍵字段,例如page,count看結果是否是會正常,若是不正常,好比多了個token,或者某個字段明顯被加密,例如用戶名密碼,那麼接下來就要看JS的代碼,看究竟是哪一個函數進行了加密,通常會是原生JS代碼加密,那麼看到代碼,直接加密就行,若是是相似RSA加密,那麼就要看公鑰是從何而來,若是是請求獲得的,那麼就要往上分析請求,另外若是是發現請求headers裏面有陌生字段,或者有Cookie也要往上看請求,Cookie在哪一步設置的;
  • 接下來找到剛剛那個請求未知來源的信息,例如Cookie或者某個加密須要的公鑰等等,看看上面某個請求是否是已經包含,依次類推。

 

2 App的分析

而後是App類的,使用的工具是Charles,手機和電腦在一個局域網內,先用Charles配置好端口,而後手機設置代理,ip爲電腦的ip,端口爲設置的端口,而後若是手機上請求網絡內容時,Charles會顯示相應地請求,那麼就ok了,分析的大致邏輯基本一致,限制會相對少不少,可是也有幾種狀況須要注意:

 

  • 加密,App有時候也有一些加密的字段,這個時候,通常來說都會進行反編譯進行分析,找到對應的代碼片斷,逆推出加密方法;
  • gzip壓縮或者base64編碼,base64編碼的辨別度較高,有時候數據被gzip壓縮了,不過Charles都是有自動解密的;
  • https證書,有的https請求會驗證證書,Charles提供了證書,能夠在官網找到,手機訪問,而後信任添加就能夠。

 

6、效率問題的取捨

通常來說在抓取大量數據,例如全網抓取京東的評論,微博全部人的信息,微博信息,關注關係等等,這種上十億到百億次設置千億次的請求必須考慮效率,否者一天只有86400秒,那麼一秒鐘要抓100次,一天也才864w次請求,也須要100多天才能到達十億級別的請求量。

涉及到大規模的抓取,必定要有良好的爬蟲設計,通常不少開源的爬蟲框架也都是有限制的,由於中間涉及到不少其餘的問題,例如數據結構,重複抓取過濾的問題,固然最重要的是要把帶寬利用滿,因此分佈式抓取很重要,接下來我會有一篇專門講分佈式的爬蟲設計,分佈式最重要的就是中間消息通訊,若是想要抓的越多越快,那麼對中間的消息系統的吞吐量要求也越高。

可是對於一些不太大規模的抓取就沒要用分佈式的一套,比較消耗時間,基本只要保證單機器的帶寬可以利用滿就沒問題,因此作好併發就能夠,另外對於數據結構也要有必定的控制,不少人寫程序,內存越寫越大,抓取愈來愈慢,可能存在的緣由就包括,一個是用了內存存一些數據沒有進行釋放,第二個可能有一些hashset的判斷,最後判斷的效率愈來愈低,好比用bloomfilter替換就會優化不少

相關文章
相關標籤/搜索