如何設(shè)計(jì)一個(gè)復(fù)雜的分布式爬蟲(chóng)系統(tǒng)?
一個(gè)復(fù)雜的分布式爬蟲(chóng)系統(tǒng)由很多的模塊組成,每個(gè)模塊是一個(gè)獨(dú)立的服務(wù)(SOA架構(gòu)),所有的服務(wù)都注冊(cè)到Zookeeper來(lái)統(tǒng)一管理和便于線上擴(kuò)展。模塊之間通過(guò)thrift(或是protobuf,或是soup,或是json,等)協(xié)議來(lái)交互和通訊。
Zookeeper負(fù)責(zé)管理系統(tǒng)中的所有服務(wù),簡(jiǎn)單的配置信息的同步,同一服務(wù)的不同拷貝之間的負(fù)載均衡。它還有一個(gè)好處是可以實(shí)現(xiàn)服務(wù)模塊的熱插拔。
URLManager是爬蟲(chóng)系統(tǒng)的核心。負(fù)責(zé)URL的重要性排序,分發(fā),調(diào)度,任務(wù)分配。單個(gè)的爬蟲(chóng)完成一批URL的爬取任務(wù)之后,會(huì)找 URLManager要一批新的URL。一般來(lái)說(shuō),一個(gè)爬取任務(wù)中包含幾千到一萬(wàn)個(gè)URL,這些URL***是來(lái)自不同的host,這樣,不會(huì)給一個(gè) host在很短一段時(shí)間內(nèi)造成高峰值。
ContentAcceptor負(fù)責(zé)收集來(lái)自爬蟲(chóng)爬到的頁(yè)面或是其它內(nèi)容。爬蟲(chóng)一般將爬取的一批頁(yè)面,比如,一百個(gè)頁(yè)面,壓縮打包成一個(gè)文件,發(fā)送給ContentAcceptor。ContentAcceptor收到后,解壓,存儲(chǔ)到分布式文件系統(tǒng)或是分布式數(shù)據(jù)庫(kù),或是直接交給 ContentParser去分析。
CaptchaHandler負(fù)責(zé)處理爬蟲(chóng)傳過(guò)來(lái)的captcha,通過(guò)自動(dòng)的captcha識(shí)別器,或是之前識(shí)別過(guò)的captcha的緩存,或是通過(guò)人工打碼服務(wù),等等,識(shí)別出正確的碼,回傳給爬蟲(chóng),爬蟲(chóng)按照定義好的爬取邏輯去爬取。
RobotsFileHandler負(fù)責(zé)處理和分析robots.txt文件,然后緩存下來(lái),給ContentParser和 URLManager提供禁止爬取的信息。一個(gè)行為端正的爬蟲(chóng),原則上是應(yīng)該遵守robots協(xié)議。但是,現(xiàn)在大數(shù)據(jù)公司,為了得到更多的數(shù)據(jù),基本上遵守這個(gè)協(xié)議的不多。robots文件的爬取,也是通過(guò)URLManager作為一種爬取類型讓分布式爬蟲(chóng)去爬取的。
ProxyManager負(fù)責(zé)管理系統(tǒng)用到的所有Proxy,說(shuō)白了,負(fù)責(zé)管理可以用來(lái)爬取的IP。爬蟲(chóng)詢問(wèn)ProxyManager,得到一批 Proxy IP,然后每次訪問(wèn)的時(shí)候,會(huì)采用不同的IP。如果遇到IP被屏蔽,即時(shí)反饋給ProxyManager,ProxyManager會(huì)根據(jù)哪個(gè)host屏蔽了哪個(gè)IP做實(shí)時(shí)的聰明的調(diào)度。
Administor負(fù)責(zé)管理整個(gè)分布式爬蟲(chóng)系統(tǒng)。管理者通過(guò)這個(gè)界面來(lái)配置系統(tǒng),啟動(dòng)和停止某個(gè)服務(wù),刪除錯(cuò)誤的結(jié)果,了解系統(tǒng)的運(yùn)行情況,等等。
各種不同類型的爬取任務(wù),比如,像給一個(gè)URL爬取一個(gè)頁(yè)面( NormalCrawler),像需要用戶名和密碼注冊(cè)然后才能爬取( SessionCrawler ),像爬取時(shí)先要輸入驗(yàn)證碼( CaptchaCrawler ),像需要模擬用戶的行為來(lái)爬取( Simulator ),像移動(dòng)頁(yè)面和內(nèi)容爬取( MobileCrawler ),和像App內(nèi)內(nèi)容的爬取( AppCrawler),需要不同類型的爬蟲(chóng)來(lái)爬取。當(dāng)然,也可以開(kāi)發(fā)一個(gè)通用的爬蟲(chóng),然后根據(jù)不同的類型實(shí)施不同的策略,但這樣一個(gè)程序內(nèi)的代碼復(fù)雜,可擴(kuò)展性和可維護(hù)性不強(qiáng)。
一個(gè)爬蟲(chóng)內(nèi)部的爬取邏輯,通過(guò)解釋從配置文件 CrawlLogic 來(lái)的命令來(lái)實(shí)現(xiàn),而不是將爬取邏輯硬編碼在爬蟲(chóng)程序里面。對(duì)于復(fù)雜的爬取邏輯,甚至可以通過(guò)用代碼寫的插件來(lái)實(shí)現(xiàn)。
ContentParser根據(jù)URLExtractionRules來(lái)抽取需要繼續(xù)爬取的URL,因?yàn)閒ocus的爬蟲(chóng)只需要爬取需要的數(shù)據(jù),不是網(wǎng)站上的每個(gè)URL都需要爬取。ContentParser還會(huì)根據(jù)FieldExtractionRules來(lái)抽取感興趣的數(shù)據(jù),然后將原始數(shù)據(jù)結(jié)構(gòu)化。由于動(dòng)態(tài)生成的頁(yè)面很多,很多數(shù)據(jù)是通過(guò)Javascript顯示出來(lái)的,需要JavascriptEngine來(lái)幫助分析頁(yè)面。這兒需要提及下,有些頁(yè)面大量使用AJAX來(lái)實(shí)時(shí)獲取和展示數(shù)據(jù),那么,需要一個(gè)能解釋Javascript的爬蟲(chóng)類型來(lái)處理這些有AJAX的情形。
為了監(jiān)控整個(gè)系統(tǒng)的運(yùn)行情況和性能,需要 Monitor 系統(tǒng)。為了調(diào)試系統(tǒng),保障系統(tǒng)安全有據(jù)可循,需要 Logger 系統(tǒng)。有了這些,系統(tǒng)才算比較完備。
所有的數(shù)據(jù)會(huì)存在分布式文件系統(tǒng)或是數(shù)據(jù)庫(kù)中,這些數(shù)據(jù)包括URL( URLRepo),Page( PageRepo )和Field( FieldRepo ),至于選擇什么樣的存儲(chǔ)系統(tǒng),可以根據(jù)自己現(xiàn)有的基礎(chǔ)設(shè)施和熟悉程度而定。
為了擴(kuò)大爬蟲(chóng)系統(tǒng)的吞吐量,每個(gè)服務(wù)都可以橫向擴(kuò)展,包括橫向復(fù)制,或是按URL來(lái)分片(sharding)。由于使用了Zookeeper,給某個(gè)服務(wù)增加一個(gè)copy,只用啟動(dòng)這個(gè)服務(wù)就可以了,剩下的Zookeeper會(huì)自動(dòng)處理。
這里只是給出了復(fù)雜分布式爬蟲(chóng)系統(tǒng)的大框架,具體實(shí)現(xiàn)的時(shí)候,還有很多的細(xì)節(jié)需要處理,這時(shí),之前做過(guò)爬蟲(chóng)系統(tǒng),踩過(guò)坑的經(jīng)驗(yàn)就很重要了。