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=[]
到目前為止, 這個網路爬蟲的基本架構已經準備好了,下面就要開始構建實際的快取了。