1. 程式人生 > >Python爬蟲讀書筆記——下載快取(5)

Python爬蟲讀書筆記——下載快取(5)

為了支援快取,需要修改之前編寫的download函式,使其在URL下載前進行快取檢查。另外,需要把限速功能移至函式內部,只有在真正發生下載時才會觸發限速,而在載入快取時不會觸發。

為了避免每次下載都要傳入多個引數,我們藉此機會將download函式重構為一個類,這樣引數只需在構造方法中設定一次,就能在後續下載時多次複用。

支援快取功能的程式碼實現:

class Downloader:
    def __init__(self,delay=5,user_agent='wswp',proxies=None,num_retries=1,cache=None):
        self.throttle=Throttle(delay)
        self.user_agent=user_agent
        self.proxies=proxies
        self.num_retries=num_retries
        self.cache=cache

    def __call__(self,url):
        result=None
        if self.cache:
            try:
                result=self.cache[url]
            except KeyError:
                #url不可以利用在cache中
                pass
            else:
                if self.num_retries>0 and 500<=result['code']<600:
                    #server error so ignore result from cache and re-download
                    result=None
        if result is None:
            #沒有從cache中下載結果,所以仍然需要下載
            self.throttle.wait(url)
            proxy=random.choice(self.proxies) if self.proxies
                else None
            headers={'User-agent':self.user_agent}
            result=self.download(url,headers,proxy,self.num_retries)
            if self.cache:
                #在cache中儲存結果
                self.cache[url]=result
            return result['html']
    def download(self,url,headers,proxy,num_retries,data=None):
        ...
    return{'html':html,'code':code}

前面程式碼中的Download類有一個比較有意思的部分,那就是 __call__ 特殊方法,在該方法中我們實現了下載前檢查快取的功能。 該方法首先會檢查快取是否已經定義。如果已經定義,則檢查之前是否已經快取了該URL。 如果該URL己被快取,則檢查之前的下載中是否遇到了服務端錯誤。最後,如果也沒有發生過服務端錯誤,則表明該快取結果可用。如果上述檢查中的 任何一項失敗,都需要正常下載該URL,然後將得到的結果新增到快取中。

這裡的 download方法和之前的download 函式基本一樣, 只是在返回下載 的HTML 時額外返回了HTTP 狀態碼, 以便在快取中儲存錯誤碼。 當然,如果你只需要一個簡單的下載功能, 而不需要限速或快取的話, 可以直接呼叫該方法, 這樣就不會通過 __call__ 方法呼叫了。

而對於 cache 類, 我們可以通過呼叫 result= cache [url]從cache中載入資料,並通過 cache[url] =result 向cache中儲存結果。 大家應該很熟悉這種便捷的介面寫法, 因為這也是Python 內建字典資料型別的使用方式。為了支援該介面 ,我們的 cache 類需要定義__getitem__()和 __setitem__()這兩個特殊的類方法。

此外,為了支援快取功能, 連結爬蟲的程式碼也需要進行一些微調,包括新增 cache 引數、 移除限速以及將 download 函式替換為新的類等, 如下面的 程式碼所示。

def link_crawler(...,cache=None):
    crawl_queue=[seed_url]
    seen={seed_url:0}
    num_urls=0
    rp=get_robots(seed_url)
    D=Downloader(delay=delay,user_agent=user_agent,proxies=proxies,num_retires=num_retries,cache=cache)
    while crawl_queue:
        url=crawl_queue.pop()
        depth=seen[url]
        #檢查url通過robot.txt限制
        if rp.can_fetch(user_agent,url):
            html=D(url)
            links=[]

到目前為止, 這個網路爬蟲的基本架構已經準備好了,下面就要開始構建實際的快取了。