修改 response.request.meta 只是改动了一个 Python 对象。要真正再下载一次,必须把另一个 Request 交给 Scrapy 去调度。

如果某个 GET 由回调明确决定重试,Scrapy 公开的重试辅助函数可以把重试计数带到新请求上:

from scrapy.downloadermiddlewares.retry import get_retry_request

def retry_through(self, response, proxy_url):
    retry = get_retry_request(
        response.request,
        spider=self,
        reason='choose_another_proxy',
    )
    if retry is None:
        return None
    retry.meta['proxy'] = proxy_url
    retry.headers.pop('Proxy-Authorization', None)
    return retry

这是一个 spider 辅助函数。调用方必须在拿到结果 Request 时将其返回或 yield。返回 None 表示在适用的上限内该辅助函数拒绝了再次重试。

重试辅助函数会复制该请求、更新其重试计数,并给出适合重试的调度器行为。若只是把同一 URL 当作普通新请求 yield,反而可能被去重过滤拦下。

请使用已启用的 HttpProxyMiddleware 所支持的代理 URL。对于允许的公开 GET 请求重试,HTTP 代理列表中未认证的 HTTP 候选即可提供 proxy_url。清除先前附加的 proxy-authorization 字段,可避免把旧中间人的请求头带进这次选择;在适用时让中间件根据新的代理 URL 推导出新的账号。

把这一 callback 层面的选择与 RetryMiddleware 对其配置故障的自动处理分开。明确由哪一层负责重试,避免一次操作消耗两套彼此独立的预算。该示例针对可重放的 GET 工作,并不承诺重复任意已提交事务是安全的。

相关文章