外行學 Python 爬蟲 第四篇 URL 去重

當你可以從網站上獲取網頁,也可以將網頁中有效的信息提取出來以後,接下來你會做什麼?我想它一定是一個肯定的答案『獲取整個網站的內容』,畢竟只獲取網站上一個網頁的內容聽起來和看起來都不是那麼的高大上,只有將整個網站的內容提取出來它才能稱得上爬蟲這個有科技感和高大上的名字。

要獲取整個網站的內容,首先需要通過一個網址來獲取其他的網址,這個我們可以使用上節解析內容的知識,從當前網頁中解析出所含有的鏈接,從而根據每個網頁中對其他網頁的連接一層層獲取整個網站的內容。此時我們會遇到一個問題,就是多個網頁中可能含有相同的網頁鏈接,此時需要將這個相同的鏈接識別出來,畢竟我們不想浪費珍貴的服務器資源去重複讀取和解析同一個網頁,要解決這個問題就需要通過 URL 去重 來實現。

在 Python 中 URL 去重可以通過以下幾個方式來實現:

  1. 將 URL 保存在集合 (set) 中,使用集合的特性來去重。
  2. 使用布隆過濾器來對 URL 去重。

對 URL 去重,還有將 URL 使用 MD5 等方法哈希後保存在 set 中的方法,原理與直接保存在 set 中相同,只是節省了內存空間。

使用集合進行去重

使用集合進行去重的優點是方便無需編寫代碼直接使用 python 內置的數據類型 set 即可,缺點是佔用內存空間,雖然可以通過 MD5 等哈希算法來減少內存的佔用但是當 url 的數量達到一定數量級的時候還是會佔用大量的內存空間。

使用集合進行 url 去重時,只需在每次需要爬取該 url 時判斷該 url 是否在集合中,若不在獲取網頁信息並將該 url 放入集合中,若存在則跳過該 url 即可。

當前使用的代碼如下:

    def __find_url(self, html):
        for link in html.find_all(name='a', href=re.compile(r'https?://list|item.szlcsc.+')):
            if len(self.__url_set) > self.__max_url_count:
                return
            url = link.get('href')
            if url not in self.__url_set:
                self.__url_set.add(url)
                self.__url_queue.put(url)

使用布隆過濾器進行 url 去重

布隆過濾器在空間和時間上具有巨大的優勢,它實際上是一個很長的二進制向量和一系列隨機映射函數,因此佔用的內存空間是固定的不會隨 url 的增長而增長。同時它的確定也很明顯有一定的誤識別率且無法從布隆過濾器中刪除已經添加的元素。

在 GitHub 上已經有人使用 python 實現了布隆過濾器,我們只需要直接使用該代碼即可,布隆濾波器 源碼

將其應用於 url 去重的示例代碼如下:

    def __find_url(self, current_url, html):
        for link in html.find_all(name='a', href=re.compile(r'https?://list|item.szlcsc.+')):
            url = link.get('href')
            if url not in self.bloomfilter:
                if self.__url_queue.qsize() < self.__max_url_count:
                    self.bloomfilter.add(url)
                    self.__url_queue.put(url)
                else:
                    self.__url_queue.put(current_url)
                    return

由於布隆過濾器存在一定的誤算率「隨着存入的元素數量增加,誤算率隨之增加」,因此布隆過濾器不適用於大量網頁且對數據要求比較嚴格的場合。

在大多數場合我們使用集合來對 url 去重已經足夠使用了,以一個 url 平均長度 100 字節來算,一千萬條 url 使用集合進行去重所需要用到的內存空間不過也就是 1G,對現在的服務器或臺式機來說應該不算太大的壓力,且一千萬的 url 已經算比較大的網站了。當 url 大於這個數的時候我想對數據的準確性也就要求不是那麼高了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章