2015-09-19 140 views
2

對於我試圖抓取的頁面,我有時會在我的響應中返回一個「佔位符」頁面,其中包含一些JavaScript,它會自動重新加載,直到它獲得真實頁面。我可以檢測到這種情況,並且我想重新嘗試下載和抓取頁面。我在我的CrawlSpider使用的邏輯是這樣的:Scrapy CrawlSpider重試刮

def parse_page(self, response): 
    url = response.url 

    # Check to make sure the page is loaded 
    if 'var PageIsLoaded = false;' in response.body: 
     self.logger.warning('parse_page encountered an incomplete rendering of {}'.format(url)) 
     yield Request(url, self.parse, dont_filter=True) 
     return 

    ... 
    # Normal parsing logic 

然而,這似乎是在重試邏輯被稱爲一個新的請求發出後,頁面和它們含有不抓取的鏈接或刮掉。我的想法是,通過使用CrawlSpider使用的self.parse來應用爬網規則和dont_filter=True,我可以避免重複的過濾器。但與DUPEFILTER_DEBUG = True,我可以看到重試請求被過濾掉。

我錯過了什麼,還是有更好的方法來處理這個問題?如果可能的話,我想避免使用類似飛濺的動態js渲染的複雜性,而且這隻會間歇性地發生。

回答

5

我會考慮改爲使用custom Retry Middleware--類似於built-in one

樣品執行(未測試):

import logging 

logger = logging.getLogger(__name__) 


class RetryMiddleware(object): 
    def process_response(self, request, response, spider): 
     if 'var PageIsLoaded = false;' in response.body: 
      logger.warning('parse_page encountered an incomplete rendering of {}'.format(response.url)) 
      return self._retry(request) or response 

     return response 

    def _retry(self, request): 
     logger.debug("Retrying %(request)s", {'request': request}) 

     retryreq = request.copy() 
     retryreq.dont_filter = True 
     return retryreq 

而且不要忘了activate它。

+0

中間件工作得很漂亮。我幾乎可以重新使用內置的重試中間件,只是去掉異常代碼,並用我自己的測試代替它。再次感謝你的幫助。 – JoshAdel

+0

@JoshAdel是的,scrapy確實使一切都變得模塊化和乾淨 - 所有的管道,中間件,擴展,項目加載器,輸入和輸出處理器都是非常重要的API接口,通常是非常棘手的網頁抓取領域。很高興幫助和感謝一個有趣的問題! – alecxe