即使在收到200状态代码时重试Scrapy请求

chr*_*est 6 python scrapy web-scraping scrapy-spider

有一个我正在抓取的网站,有时会返回200,但在response.body中没有任何文本(当我尝试用Selector解析时引发一个AttributeError).

是否有一种简单的方法来检查以确保正文包含文本,如果没有,请重试请求,直到它为止?这是一些伪代码来概述我正在尝试做什么.

def check_response(response):
    if response.body != '':
        return response
    else:
        return Request(copy_of_response.request,
                       callback=check_response)
Run Code Online (Sandbox Code Playgroud)

基本上,有没有办法可以使用完全相同的属性(方法,URL,有效负载,cookie等)重复请求?

ale*_*cxe 9

遵循EAFP原则:

比许可更容易请求宽恕.这种常见的Python编码风格假设存在有效的键或属性,并且如果假设被证明是错误则捕获异常.这种干净和快速的风格的特点是存在许多try和except语句.该技术与许多其他语言(如C)共有的LBYL风格形成对比.

处理异常并使用Request以下内容生成当前URL dont_filter=True:

dont_filter(boolean) - 表示调度程序不应过滤此请求.当您想要多次执行相同的请求时,可以使用此选项来忽略重复过滤器.小心使用它,否则您将进入爬行循环.默认为False.

def parse(response):
    try:
        # parsing logic here
    except AttributeError:
        yield Request(response.url, callback=self.parse, dont_filter=True)
Run Code Online (Sandbox Code Playgroud)

您还可以复制当前请求(未测试):

new_request = response.request.copy()
new_request.dont_filter = True
yield new_request
Run Code Online (Sandbox Code Playgroud)

或者,使用replace()以下命令发出新请求:

new_request = response.request.replace(dont_filter=True)
yield new_request
Run Code Online (Sandbox Code Playgroud)


Dmi*_*riy 7

_rety()从重试中间件调用实际方法怎么样,这样它就可以作为一个正常的重试,它的所有逻辑都考虑了设置?

在设置中:

DOWNLOADER_MIDDLEWARES = {
    'scrapy.downloadermiddlewares.retry.RetryMiddleware': None,
    'scraper.middlewares.retry.RetryMiddleware': 550,
}
Run Code Online (Sandbox Code Playgroud)

那么你的重试中间件可能是这样的:

from scrapy.downloadermiddlewares.retry import RetryMiddleware \
    as BaseRetryMiddleware


class RetryMiddleware(BaseRetryMiddleware):


    def process_response(self, request, response, spider):
        # inject retry method so request could be retried by some conditions
        # from spider itself even on 200 responses
        if not hasattr(spider, '_retry'):
            spider._retry = self._retry
        return super(RetryMiddleware, self).process_response(request, response, spider)
Run Code Online (Sandbox Code Playgroud)

然后在您的成功响应回调中,您可以调用例如:

yield self._retry(response.request, ValueError, self)
Run Code Online (Sandbox Code Playgroud)