若是讓你設計一個網絡爬蟲,你怎麼避免陷入無限循環?

話說爬蟲爲何會陷入循環呢?答案很簡單,當咱們從新去解析一個已經解析過的網頁時, 就會陷入無限循環。這意味着咱們會從新訪問那個網頁的全部連接, 而後不久後又會訪問到這個網頁。最簡單的例子就是,網頁A包含了網頁B的連接, 而網頁B又包含了網頁A的連接,那它們之間就會造成一個閉環。html

那麼咱們怎樣防止訪問已經訪問過的頁面呢,答案也很簡單,設置一個標誌便可。 整個互聯網就是一個圖結構,咱們一般使用DFS(深度優先搜索)和BFS(廣度優先搜索) 進行遍歷。因此,像遍歷一個簡單的圖同樣,將訪問過的結點標記一下便可。python

爬蟲的基本思路以下
1. 根據 Url 獲取相應頁面的 Html 代碼
2. 利用正則匹配或者 Jsoup 等庫解析 Html 代碼,提取須要的內容
3. 將獲取的內容持久化到數據庫
4. 處理好中文字符的編碼問題,能夠採用多線程提升效率mysql

 

爬蟲基本原理

更寬泛意義上的爬蟲側重於若是在大量的 url 中尋找出高質量的資源,如何在有限的時間內訪問更多頁面等等。網絡爬蟲的基本工做流程以下:程序員

1.首先選取一部分精心挑選的種子URL;

2.將這些URL放入待抓取URL隊列;

3.從待抓取URL隊列中取出待抓取在URL,解析DNS,而且獲得主機的ip,並將URL對應的網頁下載下來,存儲進已下載網頁庫中。此外,將這些URL放進已抓取URL隊列。

4.分析已抓取URL隊列中的URL,分析頁面裏包含的其餘URL,而且將URL放入待抓取URL隊列,從而進入下一個循環。

有幾個概念,一個是發http請求,一個是正則匹配你感興趣的連接,一個是多線程,另外還有兩個隊列。web

來源於 該文章 的一張圖面試

爬蟲

爬蟲難點1 環路

網絡爬蟲有時候會陷入循環或者環路中,好比從頁面 A,A 連接到頁面 B,B 連接 頁面C,頁面 C 又會連接到頁面 A。這樣就陷入到環路中。sql

環路影響

  • 消耗網絡帶寬,沒法獲取其餘頁面
  • 對 Web 服務器也是負擔,可能擊垮該站點,可能阻止正經常使用戶訪問該站點
  • 即便沒有性能影響,但獲取大量重複頁面也致使數據冗餘

解決方案

1. 簡單限定爬蟲的最大循環次數,對於某 web 站點訪問超過必定閾值就跳出,避免無限循環

2. 保存一個已訪問 url 列表,記錄頁面是否被訪問過的技術
  1. 二叉樹和散列表,快速斷定某個 url 是否訪問過
  2. 存在位圖
    就是 new int[length],而後把第幾個數置爲1,表示已經訪問過了。可不能夠再優化,int 是32位,32位能夠表示32個數字。HashCode 會存在衝突的狀況,兩個 url 映射到同一個存在位上,衝突的後果是某個頁面被忽略(這比死循環的惡做用小)
  3. 保存檢查
    必定要即便把已訪問的 url 列表保存在硬盤上,防止爬蟲崩潰,內存裏的數據會丟失
  4. 集羣 ,分而治之
    多臺機器一塊兒爬蟲,能夠根據 url 計算 hashcode,而後根據 hashcode 映射到相應機器的 id (第0臺、第1臺、第2臺等等)

難點2 URL別名

有些 url 名稱不同,可是指向同一個資源。
該表格來自於 《HTTP 權威指南》數據庫

URl 1 URL 2 何時是別名
www.foo.com/bar.html www.foo.com:80/bar.html 默認端口是80
www.foo.com/~fred www.foo.com/%7Ffred %7F與~相同
www.foo.com/x.html#top www.foo.com/x.html#middle %7F與~相同
https://www.baidu.com/ https://www.BAIDU.com/ 服務器是大小寫無關
www.foo.com/index.html www.foo.com 默認頁面爲 index.html
www.foo.com/index.html 209.123.123/index.html ip和域名相同

難點3 動態虛擬空間

好比日曆程序,它會生成一個指向下一月的連接,真正的用戶是不會不停地請求下個月的連接的。可是不瞭解這內容特性的爬蟲蜘蛛可能會不斷向這些資源發出無窮的請求。json

抓取策略

通常策略是深度優先或者廣度優先。有些技術能使得爬蟲蜘蛛有更好的表現緩存

  • 廣度優先的爬行,避免深度優先陷入某個站點的環路中,沒法訪問其餘站點。
  • 限制訪問次數,限定一段時間內機器人能夠從一個 web 站點獲取的頁面數量
  • 內容指紋,根據頁面的內容計算出一個校驗和,可是動態的內容(日期,評論數目)會阻礙重複檢測
  • 維護黑名單
  • 人工監視,特殊狀況發出郵件通知
  • 動態變化,根據當前熱點新聞等等

  • 規劃化 url,把一些轉義字符、ip 與域名之類的統一

  • 限制 url 大小,環路可能會使得 url 長度增長,好比/index.html, /folder/index,html, /folder/folder/index.html …

全文索引

全文索引就是一個數據庫,給它一個單詞,它能夠馬上提供包含那個單詞的全部文字。建立了索引以後,就沒必要對文檔自身進行掃描了。

好比 文章 A 包含了 Java、學習、程序員
文章 B 包含了 Java 、Python、面試、招聘

若是搜索 Java,能夠知道獲得 文章 A 和文章 B,而沒必要對文章 A、B 全文掃描。

 

一個複雜的分佈式爬蟲系統由不少的模塊組成,每一個模塊是一個獨立的服務(SOA架構),全部的服務都註冊到Zookeeper來統一管理和便於線上擴展。模塊之間經過thrift(或是protobuf,或是soup,或是json,等)協議來交互和通信。

Zookeeper負責管理系統中的全部服務,簡單的配置信息的同步,同一服務的不一樣拷貝之間的負載均衡。它還有一個好處是能夠實現服務模塊的熱插拔。

URLManager是爬蟲系統的核心。負責URL的重要性排序,分發,調度,任務分配。單個的爬蟲完成一批URL的爬取任務以後,會找 URLManager要一批新的URL。通常來講,一個爬取任務中包含幾千到一萬個URL,這些URL最好是來自不一樣的host,這樣,不會給一個 host在很短一段時間內形成高峯值。

ContentAcceptor負責收集來自爬蟲爬到的頁面或是其它內容。爬蟲通常將爬取的一批頁面,好比,一百個頁面,壓縮打包成一個文件, 發送給ContentAcceptor。ContentAcceptor收到後,解壓,存儲到分佈式文件系統或是分佈式數據庫,或是直接交給 ContentParser去分析。

CaptchaHandler負責處理爬蟲傳過來的captcha,經過自動的captcha識別器,或是以前識別過的captcha的緩存,或是經過人工打碼服務,等等,識別出正確的碼,回傳給爬蟲,爬蟲按照定義好的爬取邏輯去爬取。

RobotsFileHandler負責處理和分析robots.txt文件,而後緩存下來,給ContentParser和 URLManager提供禁止爬取的信息。一個行爲端正的爬蟲,原則上是應該遵照robots協議。可是,如今大數據公司,爲了獲得更多的數據,基本上遵 守這個協議的很少。robots文件的爬取,也是經過URLManager做爲一種爬取類型讓分佈式爬蟲去爬取的。

ProxyManager負責管理系統用到的全部Proxy,說白了,負責管理能夠用來爬取的IP。爬蟲詢問ProxyManager,獲得一 批Proxy IP,而後每次訪問的時候,會採用不一樣的IP。若是遇到IP被屏蔽,即時反饋給ProxyManager,ProxyManager會根據哪一個host屏 蔽了哪一個IP作實時的聰明的調度。

Administor負責管理整個分佈式爬蟲系統。管理者經過這個界面來配置系統,啓動和中止某個服務,刪除錯誤的結果,瞭解系統的運行狀況,等等。

各類不一樣類型的爬取任務,好比,像給一個URL爬取一個頁面( NormalCrawler),像須要用戶名和密碼註冊而後才能爬取( SessionCrawler ),像爬取時先要輸入驗證碼( CaptchaCrawler ),像須要模擬用戶的行爲來爬取( Simulator ),像移動頁面和內容爬取( MobileCrawler ),和像App內內容的爬取( AppCrawler),須要不一樣類型的爬蟲來爬取。固然,也能夠開發一個通用的爬蟲,而後根據不一樣的類型實施不一樣的策略,但這樣一個程序內的代碼複雜, 可擴展性和可維護性不強。

一個爬蟲內部的爬取邏輯,經過解釋從配置文件 CrawlLogic 來的命令來實現,而不是將爬取邏輯硬編碼在爬蟲程序裏面。對於複雜的爬取邏輯,甚至能夠經過用代碼寫的插件來實現。

ContentParser根據URLExtractionRules來抽取須要繼續爬取的URL,由於focus的爬蟲只須要爬取須要的數 據,不是網站上的每一個URL都須要爬取。ContentParser還會根據FieldExtractionRules來抽取感興趣的數據,而後將原始數 據結構化。因爲動態生成的頁面不少,不少數據是經過Javascript顯示出來的,須要JavascriptEngine來幫助分析頁面。這兒須要說起 下,有些頁面大量使用AJAX來實時獲取和展現數據,那麼,須要一個能解釋Javascript的爬蟲類型來處理這些有AJAX的情形。

爲了監控整個系統的運行狀況和性能,須要 Monitor 系統。爲了調試系統,保障系統安全有據可循,須要 Logger 系統。有了這些,系統纔算比較完備。

全部的數據會存在分佈式文件系統或是數據庫中,這些數據包括URL( URLRepo),Page( PageRepo )和Field( FieldRepo ),至於選擇什麼樣的存儲系統,能夠根據本身現有的基礎設施和熟悉程度而定。

爲了擴大爬蟲系統的吞吐量,每一個服務均可以橫向擴展,包括橫向複製,或是按URL來分片(sharding)。因爲使用了Zookeeper,給某個服務增長一個copy,只用啓動這個服務就能夠了,剩下的Zookeeper會自動處理。

這裏只是給出了複雜分佈式爬蟲系統的大框架,具體實現的時候,還有不少的細節須要處理,這時,以前作過爬蟲系統,踩過坑的經驗就很重要了。

相關文章
相關標籤/搜索