【问题标题】:Scrapy - Break out of loop if response.status == 404Scrapy - 如果 response.status == 404 则跳出循环
【发布时间】:2015-02-24 21:05:28
【问题描述】:

如果后续 yield 请求的 response.status 为 404,我试图打破一个循环。我正在迭代页码,但不知道有多少页可用。最终我会点击一个 404 页面,我希望它打破 while 循环。我把它硬编码成 40 页,但有 40 多页

def parse(self, response):
    cat = json.loads(response.body_as_unicode())
    for c in cat:
        while **RESPONSE.STATUS == 200**:
            url = 'http://www.url.com/'+str(c)+'/'+str(page)+'.json'
            page += 1
            yield Request(url, callback=self.parse_cats)

def parse_cats(self, response):
    if response.status  == '404':
        **BREAK ABOVE LOOP**

我查看了 Request(errback=) 但不确定这是否是解决此问题的正确方法。

任何帮助将不胜感激!

【问题讨论】:

    标签: python web-scraping scrapy scrapy-spider


    【解决方案1】:

    由于 Scrapy 基于名为 twisted 的异步网络库 - 行为是非阻塞和异步的。您不能中断请求回调的循环


    您可以在蜘蛛实例上使用某种seen_404 标志。一旦看到404 状态 - 将其设置为True 并在self.seen_404True 的情况下中断循环。这不是一个可靠的解决方案,因为这又是异步的——当回调被调用并且seen_404 被设置为True 时,你不会知道循环经过了多少次迭代。但是,例如,如果您知道在 404 页面之后所有下一页也将具有 404 状态 - 那么这可能没问题:

    def parse(self, response):
        cat = json.loads(response.body_as_unicode())
        for c in cat:
            if self.seen_404:
                break
    
            url = 'http://www.url.com/'+str(c)+'/'+str(page)+'.json'
            page += 1
            yield Request(url, callback=self.parse_cats)
    
    def parse_cats(self, response):
        if response.status == '404':
            self.seen_404 = True
    

    另一种选择是使其同步,方法是在请求本身(在meta 内部)传递请求列表(队列):

    def parse(self, response):
        cat = json.loads(response.body_as_unicode())
        urls = ['http://www.url.com/%s/%s.json' % (c, page) 
                for page, c in enumerate(cat)]  # if you want page to start with 1: enumerate(cat, start=1)
    
        url = urls.pop(0)
        yield Request(url, meta={'urls': urls}, callback=self.parse_cats)
    
    def parse_cats(self, response):
        if response.status == '404':
            # stop crawling
            raise CloseSpider('404 found at %s' % response.url)
    
        urls = response.meta['urls']
        try:
            url = urls.pop(0)
        except IndexError:
            raise CloseSpider('No more urls to go')
    
        yield Request(url, meta={'urls': urls}, callback=self.parse_cats)
    

    【讨论】:

    • 有道理,谢谢你的澄清。我将使用 self.seen_404 变量至少停止生成新的 404 请求。我还将它添加到 settings.py 以使scrapy按顺序处理迭代请求。 DEPTH_PRIORITY = 1 SCHEDULER_DISK_QUEUE = 'scrapy.squeue.PickleFifoDiskQueue' SCHEDULER_MEMORY_QUEUE = 'scrapy.squeue.FifoMemoryQueue'
    • @EricValente 请查看更新。希望这也有意义。
    • 我要试一试!假设它会因为我们使其同步而刮得更慢?
    • @EricValente 正确,理论上它应该更慢,但取决于您需要检查多少 url,直到 404 ..
    • @EricValente 注意,我添加了另一个编辑 - 在底部 yield 行缺少 meta={'urls': urls}
    【解决方案2】:

    在 Scrapy 2.4.1 中,如果 response.status 不成功,默认情况下 HttpErrorMiddleware 将停止爬虫

    【讨论】:

      猜你喜欢
      • 2015-12-28
      • 2022-11-15
      • 2018-08-20
      • 2015-08-20
      • 2014-01-23
      • 1970-01-01
      • 2021-08-31
      • 2014-11-09
      • 2020-08-08
      相关资源
      最近更新 更多