網絡爬蟲-URL去重

轉載自:http://hi.baidu.com/shirdrn/blog/item/40ed0fb1ceac4d5c0923029d.html

在爬蟲啓動工作的過程中,我們不希望同一個網頁被多次下載,因爲重複下載不僅會浪費CPU機時,還會爲搜索引擎系統增加負荷。而想要控制這種重複性下載問題,就要考慮下載所依據的超鏈接,只要能夠控制待下載的URL不重複,基本可以解決同一個網頁重複下載的問題。

非常容易想到,在搜索引擎系統中建立一個全局的專門用來檢測,是否某一個URL對應的網頁文件曾經被下載過的URL存儲庫,這就是方案。

接着要考慮的就是如何能夠更加高效地讓爬蟲工作,確切地說,讓去重工作更加高效。如果實現去重,一定是建立一個URL存儲庫,並且已經下載完成的URL在進行檢測時候,要加載到內存中,在內存中進行檢測一定會比直接從磁盤上讀取速度快很多。

我們先從最簡單的情況說起,然後逐步優化,最終得到一個非常不錯的解決方案。

第一,基於磁盤的順序存儲。

這裏,就是指把每個已經下載過的URL進行順序存儲。你可以把全部已經下載完成的URL存放到磁盤記事本文件中。每次有一個爬蟲線程得到一個任務URL開始下載之前,通過到磁盤上的該文件中檢索,如果沒有出現過,則將這個新的URL寫入記事本的最後一行,否則就放棄該URL的下載。

這種方式幾乎沒有人考慮使用了,但是這種檢查的思想是非常直觀的。試想,如果已經下載了100億網頁,那麼對應着100億個鏈接,也就是這個檢查URL是否重複的記事本文件就要存儲這100億URL,況且,很多URL字符串的長度也不小,佔用存儲空間不說,查找效率超級低下,這種方案肯定放棄。

第二,基於Hash算法的存儲。

對每一個給定的URL,都是用一個已經建立好的Hash函數,映射到某個物理地址上。當需要進行檢測URL是否重複的時候,只需要將這個URL進行Hash映射,如果得到的地址已經存在,說明已經被下載過,放棄下載,否則,將該URL及其Hash地址作爲鍵值對存放到Hash表中。

這樣,URL去重存儲庫就是要維護一個Hash表,如果Hash函數設計的不好,在進行映射的時候,發生碰撞的機率很大,則再進行碰撞的處理也非常複雜。而且,這裏使用的是URL作爲鍵,URL字符串也佔用了很大的存儲空間。

第三,基於MD5壓縮映射的存儲。

MD5算法是一種加密算法,同時它也是基於Hash的算法。這樣就可以對URL字符串進行壓縮,得到一個壓縮字符串,同時可以直接得到一個Hash地址。另外,MD5算法能夠將任何字符串壓縮爲128位整數,並映射爲物理地址,而且MD5進行Hash映射碰撞的機率非常小,這點非常好。從另一個方面來說,非常少的碰撞,對於搜索引擎的爬蟲是可以容忍的。況且,在爬蟲進行檢測的過程中,可以通過記錄日誌來保存在進行MD5時發生碰撞的URL,通過單獨對該URL進行處理也是可行的。

下面就是是對URL進行壓縮的MD5方法,對URL字符串進行壓縮:

public static String md5(String string) {
   char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',
       'e', 'f' };
   try {
    byte[] bytes = string.getBytes();
    MessageDigest messageDigest = MessageDigest.getInstance("MD5");
    messageDigest.update(bytes);
    byte[] updateBytes = messageDigest.digest();
    int len = updateBytes.length;
    char myChar[] = new char[len * 2];
    int k = 0;
    for (int i = 0; i < len; i++) {
     byte byte0 = updateBytes[i];
     myChar[k++] = hexDigits[byte0 >>> 4 & 0x0f];
     myChar[k++] = hexDigits[byte0 & 0x0f];
    }
    return new String(myChar);
   } catch (Exception e) {
    return null;
   }
}

在Java中有一個Map類非常好,你可以將壓縮後的URL串作爲Key,而將Boolean作爲Value進行存儲,然後將工作中的Map在爬蟲停止工作後序列化到本地磁盤上;當下一次啓動新的爬蟲任務的時候,再將這個Map反序列化到內存中,供爬蟲進行URL去重檢測。

第四,基於嵌入式Berkeley DB的存儲。

Berkeley DB的特點就是隻存儲鍵值對類型數據,這和URL去重有很大關係。去重,可以考慮對某個鍵,存在一個值,這個值就是那個鍵的狀態。

使用了Berkeley DB,你就不需要考慮進行磁盤IO操作的性能損失了,這個數據庫在設計的時候很好地考慮了這些問題,並且該數據庫支持高併發,支持記錄的順序存儲和隨機存儲,是一個不錯的選擇。

URL去重存儲庫使用Berkeley DB,壓縮後的URL字符串作爲Key,或者直接使用壓縮後的URL字節數組作爲Key,對於Value可以使用Boolean,一個字節,或者使用字節數組,實際Value只是一個狀態標識,減少Value存儲佔用存儲空間。

第五,基於布隆過濾器(Bloom Filter)的存儲。

使用布隆過濾器,設計多個Hash函數,也就是對每個字符串進行映射是經過多個Hash函數進行映射,映射到一個二進制向量上,這種方式充分利用了比特位。

不過,我沒有用過這種方式,有機會可以嘗試一下。可以參考Google的http://www.googlechinablog.com/2007/07/bloom-filter.html

發佈了106 篇原創文章 · 獲贊 29 · 訪問量 42萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章