手把手教你寫網路爬蟲(2):迷你爬蟲架構

發表於2018-04-27

介紹

大家好!回顧上一期,我們在介紹了爬蟲的基本概念之後,就利用各種工具橫衝直撞的完成了一個小爬蟲,目的就是猛、糙、快,方便初學者上手,建立信心。對於有一定基礎的讀者,請不要著急,以後我們會學習主流的開源框架,打造出一個強大專業的爬蟲系統!不過在此之前,要繼續打好基礎,本期我們先介紹爬蟲的種類,然後選取最典型的通用網路爬蟲,為其設計一個迷你框架。有了自己對框架的思考後,再學習複雜的開源框架就有頭緒了。

今天我們會把更多的時間用在思考上,而不是一根筋的coding。用80%的時間思考,20%的時間敲鍵盤,這樣更有利於進步。

語言&環境

語言:帶足彈藥,繼續用Python開路!

threadingthreading庫可以在單獨的執行緒中執行任何的在Python中可以呼叫的物件。Python 2.x中的thread模組已被廢棄,使用者可以使用threading模組代替。在Python 3中不能再使用thread模組。為了相容性,Python 3將thread重新命名為_thread。

queuequeue模組中提供了同步的、執行緒安全的佇列類,包括FIFO(先入先出)佇列Queue,LIFO(後入先出)佇列LifoQueue,和優先順序佇列PriorityQueue。這些佇列都實現了鎖原語,能夠在多執行緒中直接使用。可以使用佇列來實現執行緒間的同步。

rePython 自1.5版本起增加了re模組,它提供Perl風格的正規表示式模式。re模組使 Python語言擁有全部的正規表示式功能。

argparsePython用於解析命令列引數和選項的標準模組,用於代替已經過時的optparse模組。argparse模組的作用是用於解析命令列引數。

configparser讀取配置檔案的模組。

爬蟲的種類

網路爬蟲按照系統結構和實現技術,大致可以分為以下幾種型別:通用網路爬蟲(General Purpose Web Crawler)、聚焦網路爬蟲(Focused Web Crawler)、增量式網路爬蟲(Incremental Web Crawler)、深層網路爬蟲(Deep Web Crawler)。實際的網路爬蟲系統通常是幾種爬蟲技術相結合實現的。

通用網路爬蟲

通用網路爬蟲又稱全網爬蟲(Scalable Web Crawler),爬取物件從一些種子 URL 擴充到整個 Web。主要為門戶站點搜尋引擎和大型 Web 服務提供商採集資料。

通用網路爬蟲的結構大致可以分為頁面爬取模組 、頁面分析模組、連結過濾模組、頁面儲存模組、URL 佇列、初始 URL 集合幾個部分。為提高工作效率,通用網路爬蟲會採取一定的爬取策略。 常用的爬取策略有:深度優先策略、廣度優先策略。

1) 深度優先策略(DFS):其基本方法是按照深度由低到高的順序,依次訪問下一級網頁連結,直到不能再深入為止。

2) 廣度優先策略(BFS):此策略按照網頁內容目錄層次深淺來爬取頁面,處於較淺目錄層次的頁面首先被爬取。 當同一層次中的頁面爬取完畢後,爬蟲再深入下一層繼續爬取。

聚焦網路爬蟲

聚焦網路爬蟲(Focused Crawler),又稱主題網路爬蟲(Topical Crawler),是指選擇性地爬取那些與預先定義好的主題相關頁面的網路爬蟲。 和通用網路爬蟲相比,聚焦爬蟲只需要爬取與主題相關的頁面,極大地節省了硬體和網路資源,儲存的頁面也由於數量少而更新快,還可以很好地滿足一些特定人群對特定領域資訊的需求。我們之前爬的歌單就屬於這一種。

增量式網路爬蟲

增量式網路爬蟲(Incremental Web Crawler)是 指 對 已 下 載 網 頁 採 取 增 量式更新和只爬取新產生的或者已經發生變化網頁的爬蟲,它能夠在一定程度上保證所爬取的頁面是儘可能新的頁面。 和週期性爬取和重新整理頁面的網路爬蟲相比,增量式爬蟲只會在需要的時候爬取新產生或發生更新的頁面 ,並不重新下載沒有發生變化的頁面,可有效減少資料下載量,及時更新已爬取的網頁,減小時間和空間上的耗費,但是增加了爬取演算法的複雜度和實現難度。現在比較火的輿情爬蟲一般都是增量式網路爬蟲。

深網爬蟲

Web 頁面按存在方式可以分為表層網頁(Surface Web)和深層網頁(Deep Web,也稱 Invisible Web Pages 或 Hidden Web)。 表層網頁是指傳統搜尋引擎可以索引的頁面,以超連結可以到達的靜態網頁為主構成的 Web 頁面。Deep Web 是那些大部分內容不能通過靜態連結獲取的、隱藏在搜尋表單後的,只有使用者提交一些關鍵詞才能獲得的 Web 頁面。例如那些使用者註冊後內容才可見的網頁就屬於 Deep Web。

一個迷你框架

下面以比較典型的通用爬蟲為例,分析其工程要點,設計並實現一個迷你框架。架構圖如下:

程式碼結構:

config_load.py    配置檔案載入

crawl_thread.py    爬取執行緒

mini_spider.py    主執行緒

spider.conf    配置檔案

url_table.py    url佇列、url表

urls.txt    種子url集合

webpage_parse.py    網頁分析

webpage_save.py    網頁儲存

看看配置檔案裡有什麼內容:

spider.conf

Step 1. 採用BFS還是DFS?

理論上,這兩個演算法都能夠在大致相同的時間裡爬取整個網際網路上的內容。但顯然各個網站最重要的網頁應該是它的首頁。在極端情況下,如果只能下載非常有限的網頁,那麼應該下載的所有網站的首頁,如果把爬蟲再擴大些,應該爬取從首頁直接連結的網頁,因為這些網頁是網站設計者自己認為相當重要的網頁。在這個前提下,顯然BFS明顯優於DFS。事實上在搜尋引擎的爬蟲裡,主要採用的就是BFS。我們的框架採取這種策略。

抓取深度可以通過配置檔案中的max_depth設定,只要沒到達指定深度,程式就會不停的將解析出的url放入佇列中:

mini_spider.py

Step 2. 初始URL集合、URL佇列

我們來看看通用爬蟲如何下載整個網際網路。假設從一家入口網站的首頁出發,先下載這個網頁(深度=0),然後通過分析這個網頁,可以找到頁面裡的所有超連結,也就等於知道了這家入口網站首頁所直接連線的全部網頁,諸如京東理財、京東白條,京東眾籌等(深度=1)。接下來訪問、下載並分析京東理財等網頁,又能找到其他相連的網頁(深度=2)。讓計算機不停的做下去,就能下載整個網站。

在這個過程中,我們需要一個“初始URL集合”儲存門戶的首頁,還需要一個“URL佇列”儲存分析網頁得到的超連結。

mini_spider.py

url_table.py

Step 3. 記錄哪些網頁已經下載過的小本本——URL表。

在網際網路上,一個網頁可能被多個網頁中的超連結所指向。這樣在遍歷網際網路這張圖的時候,這個網頁可能被多次訪問到。為了防止一個網頁被下載和解析多次,需要一個URL表記錄哪些網頁已經下載過。再遇到這個網頁的時候,我們就可以跳過它。

crawl_thread.py

Step 4. 多個抓取執行緒

為了提升爬蟲效能,需要多個抓取執行緒,從URL佇列獲取連結進行處理。多執行緒並沒什麼毛病,但Python的多執行緒可能會引起很多人的質疑,這源於Python設計之初的考慮:GIL。GIL的全稱是Global Interpreter Lock(全域性直譯器鎖),某個執行緒想要執行,必須先拿到GIL,並且在一個Python程式中,GIL只有一個。結果就是Python裡一個程式永遠只能同時執行一個執行緒,這就是為什麼在多核CPU上,Python的多執行緒效率並不高。那麼我們為什麼還要用Python多執行緒呢?

CPU密集型程式碼(各種迴圈處理、編解碼等等),在這種情況下,由於計算工作多,ticks計數很快就會達到閾值,然後觸發GIL的釋放與再競爭(多個執行緒來回切換當然是需要消耗資源的),Python下的多執行緒對CPU密集型程式碼並不友好。

IO密集型程式碼(檔案處理、網路爬蟲等),多執行緒能夠有效提升效率(單執行緒下有IO操作會進行IO等待,造成不必要的時間浪費,而開啟多執行緒能線上程A等待時,自動切換到執行緒B,可以不浪費CPU的資源,從而能提升程式執行效率)。Python的多執行緒對IO密集型程式碼比較友好。

所以,對於IO密集的爬蟲程式,使用Python多執行緒是沒問題的。

crawl_thread.py

Step 5. 頁面分析模組

從網頁中解析出URLs或者其他有用的資料。這個是上期重點介紹的,可以參考之前的程式碼。

Step 6. 頁面儲存模組

儲存頁面的模組,目前將檔案儲存為檔案,以後可以擴充套件出多種儲存方式,如mysql,mongodb,hbase等等。

webpage_save.py

寫到這裡,整個框架已經清晰的呈現在大家眼前了,千萬不要小看它,不管多麼複雜的框架都是在這些基本要素上擴充套件出來的。

下一步

基礎知識的學習暫時告一段落,希望能夠幫助大家打下一定的基礎。下期開始為大家介紹強大成熟的爬蟲框架Scrapy,它提供了很多強大的特性來使得爬取更為簡單高效,更多精彩,敬請期待!

相關文章