手把手教你寫網路爬蟲(6) 作者:拓海 摘要:從零開始寫爬蟲,初學者的速成指南! 封面: 下麵是一個超級電腦的排行榜,如果我們能擁有其中任意一個,那麼我們就不需要搞什麼分散式系統。可是我們買不起,即使買得起,也交不起電費,所以我們只好費腦子搞分散式。 Rank System Cores Rmax ...
手把手教你寫網路爬蟲(6)
作者:拓海
摘要:從零開始寫爬蟲,初學者的速成指南!
封面:
下麵是一個超級電腦的排行榜,如果我們能擁有其中任意一個,那麼我們就不需要搞什麼分散式系統。可是我們買不起,即使買得起,也交不起電費,所以我們只好費腦子搞分散式。
Rank |
System |
Cores |
Rmax |
Rpeak |
Power (kW) |
1 |
Tianhe-2 China |
3,120,000 |
33,862.7 |
54,902.4 |
17,808 |
2 |
Titan US |
560,640 |
17,590.0 |
27,112.5 |
8,209 |
3 |
Sequoia US |
1,572,864 |
17,173.2 |
20,132.7 |
7,890 |
4 |
K Japan |
705,024 |
10,510.0 |
11,280.4 |
12,660 |
5 |
Mira US |
786,432 |
8,586.6 |
10,066.3 |
3,945 |
分散式的本質就如上期提到的一個概念:分散式系統是若幹獨立電腦的集合,這些電腦對於用戶來說就像是單個相關係統。這就是在說,把廉價的電腦堆到一起,通過程式控制,使其整體用起來像個高性能電腦,目的就是節約成本。
對於分散式爬蟲系統來說,假設1台機器能10天爬完一個任務,如果部署10台機器,那麼1天就會完成這個任務。這樣就用可以接受的成本,讓系統的效率提高了十倍。之前介紹的單機架構是達不到這種效果的,是時候介紹新的架構了!
架構概述
與第二期介紹的通用爬蟲架構不同,下麵是一個聚焦爬蟲的架構圖,與前者相比,它不僅要保存網頁,還要提取出網頁中的指定內容。
Crawler_core 從任務隊列獲取爬蟲任務,請求網頁並將其存儲到Mongodb,同時解析出網頁中的URLs並緩存到Redis。最後通知Common-clean-platform抽取網頁的指定欄位。
Common-clean-platform 收到Crawler_core的通知後,從Mongodb中取出網頁,根據配置進行數據抽取,形成結構化的數據,保存到Mongodb。
Scheduler_manager 負責任務調度(如啟停),狀態控制(如爬取數量),redis資源清理等。
Resource_manager 封裝Mysql、Mongodb、Redis介面。Mysql存儲任務基本信息、配置文件、任務實時狀態等。Mongodb存儲網頁、結構化數據。Redis緩存隊列、集合等數據結構。
Proxy 代理伺服器。建立網路爬蟲的第一原則是:所有信息都可以偽造。你可以用非本人的郵箱發送郵件,或者通過命令行自動化滑鼠的行為。但是有一件事情是不能作假的,那就是你的IP地址。如果你在爬取的過程中不想被人發現,或者不想IP被封殺,那麼就需要使用代理。
筆者以前看過一個電影叫《Who Am I - No System Is Safe》,劇中的黑客老大“Who Am I”就用代理來隱藏自己,躲避FBI和其他黑客組織的追蹤。
不過最終他還是被抓了,看來即使用了炫酷的技術,也不是絕對安全的。
如果你也想體驗一下匿名訪問網路,可以試試Tor代理伺服器。洋蔥路由(The Onion Router)網路,常用縮寫為Tor,是一種IP 地址匿名手段。由網路志願者伺服器構建的洋蔥路由器網路,通過不同伺服器構成多個層(就像洋蔥)把客戶端包在最裡面。數據進入網路之前會被加密,因此任何伺服器都不能偷取通信數據。另外,雖然每一個伺服器的入站和出站通信都可以被查到,但是要想查出通信的真正起點和終點,必須知道整個通信鏈路上所有伺服器的入站和出站通信細節,而這基本是不可能實現的。
Tor 是人權工作者和政治避難人員與記者通信的常用手段,得到了美國政府的大力支持。當然,它經常也被用於非法活動,所以也是政府盯防的目標(雖然目前盯防得並不是很成功)。
流程式控制制 – 任務
Scheduler_manager定時讀取Mysql中的任務信息,根據任務的周期等配置進行調度,下麵是一個最基本的任務啟停流程。
- 當一個任務可以開始時,Scheduler_manager會將其基本信息(包括task_id,種子url,啟動時間等)插入Reids的任務隊列中。如果任務結束,就從隊列中刪除。
- 每個Crawler_core實例定時讀取Redis任務隊列中的任務,插入到本地的記憶體任務隊列中。
- 相同的任務可以存在於不同的Crawler_core實例中,一個Crawler_core實例中也可以有相同的任務。
- Crawler_core的抓取線程從記憶體隊列中獲得可執行的任務,依次抓取和解析。
流程式控制制 – 數據
現在每個Crawler_core實例都有了待處理的任務,接下來就要對每個任務的url進行處理了。繼續使用Redis作為公共緩存來存放URLs,多個Crawler_core實例並行存取todo集合。
- Todo集合 Crawler_core從集合中取出url進行處理,並將解析得到的url添加到todo集合中。
- Doing集合 Crawler_core從todo中取出url,都同時保存到doing中,url處理完成時被從doing中刪除。主要用於恢複數據。
- Parser todo隊列 Crawler_core將已經保存到mongodb的頁面的url發送到parser todo隊列,Parser讀取數據後進行解析。
- Filter todo隊列 Parser將已經保存到mongodb的解析結果的url發送到filter todo隊列,Filter讀取數據後進行清洗。
流程式控制制 – 狀態
藍色箭頭 業務模塊實時更新任務狀態到Redis,StateObserver讀取到Redis狀態後,更新到mysql。
紅色箭頭 ClearObserver定時讀取Mysql狀態,若任務完成或中止,則清除任務所有的Redis key。
Redis中的任務信息如下表所示:
taskId:flag:crawler:info |
||
Filed |
value |
說明 |
totalCnt |
10000 |
抓取的url總數:抓取完成,不管成功失敗,都加1 |
failCnt |
0 |
抓取的url失敗數:抓取失敗,加1 |
switch |
1 |
任務狀態:0:停止,1:啟動,2:暫停,3:暫停啟動 |
priority |
1 |
任務優先順序 |
retryCnt |
0 |
重試次數 |
status |
0 |
任務執行狀態:1:進行中,2:完成 |
Ref |
0 |
url引用數:每消費一個url,減1;生成一個url,加1。等於0則任務完成 |
maxThreadCnt |
100 |
任務的最大線程數 |
remainThreadCnt |
10 |
剩餘可用線程數 |
lastFetchTime |
1496404451532 |
上一次抓取時間 |
taskId:flag:parser:info |
||
Filed |
value |
說明 |
totalCnt |
10000 |
解析總數:解析完成,不管成功失敗,都加1 |
failCnt |
0 |
解析失敗數:解析失敗,加1 |
crawlerStatus |
0 |
爬取狀態:0:進行中,2:完成 |
ref |
10 |
url引用數:crawler每保存一個網頁,加1;parser每解析完成一個網頁,減1。等於0不說明任務完成。若crawlerStatus等於2,ref等於0,則任務完成。 |
taskId:flag:filter:info |
||
Filed |
value |
說明 |
totalCnt |
10000 |
清洗總數:清洗完成,不管成功失敗,都加1 |
failCnt |
0 |
清洗失敗數:清洗失敗,加1 |
crawlerStatus |
0 |
解析狀態:0:進行中,2:完成 |
ref |
10 |
url引用數:parser每保存一條數據,加1;filter每清洗完成一條數據,減1。等於0不說明任務完成。若parserStatus等於2,ref等於0,則任務完成。 |
流程式控制制 – failover
如果一個Crawler_core的機器掛掉了,就會開始數據恢復程式,把這台機器所有未完成的任務恢復到公共緩存中。
- 監控到192.168.0.1心跳停止。
- Master遍歷正在運行的任務: task_jdjr:1489050240345等。
- 得到doing和todo集合:
- task_jdjr:1489050240345:crawler:doing: 192.168.0.1
- task_jdjr:1489050240345:crawler:todo
- 將doing中的數據全部移動到todo中。
下一步
今天對架構和流程進行了一個概要的介紹,細節問題以後會慢慢說。下期我們就先聊聊URL去重那些事兒。