V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
warcraft1236
V2EX  ›  Python

Scrapy 的 RetryMiddleware 不生效,求教

  •  
  •   warcraft1236 · 2019-02-03 23:31:26 +08:00 · 3547 次点击
    这是一个创建于 1901 天前的主题,其中的信息可能已经有所发展或是发生改变。

    按照惯例,我先贴出来代码

    class CustomerRetryMiddleware(RetryMiddleware):
        """
            去掉了一些判断,增加了 log
        """
    
        def process_response(self, request, response, spider):
            if response.status in self.retry_http_codes:
                retries = request.meta.get('retry_times', 0) + 1
                reason = response_status_message(response.status)
                spider.logger.warn('下载中收到错误 http code:{0},丢入重试,第{1}次重试'.format(reason, retries))
                return self._retry(request, reason, spider) or response
            else:
                return response
    
        """
            去掉了 EXCEPTIONS_TO_RETRY 判断,无脑重试
        """
    
        def process_exception(self, request, exception, spider):
            retries = request.meta.get('retry_times', 0) + 1
            spider.logger.warn('下载中收到:{0},丢入重试,第{1}次重试'.format(exception.reasons, retries))
            return self._retry(request, 'CustomerRetryError', spider)
    
        def _retry(self, request, reason, spider):
            retries = request.meta.get('retry_times', 0) + 1
    
            retry_times = self.max_retry_times
    
            if 'max_retry_times' in request.meta:
                retry_times = request.meta['max_retry_times']
    
            stats = spider.crawler.stats
            if retries <= retry_times:
                spider.logger.debug("Retrying %(request)s (failed %(retries)d times): %(reason)s",
                                    {'request': request, 'retries': retries, 'reason': reason},
                                    extra={'spider': spider})
                retryreq = request.copy()
                retryreq.meta['retry_times'] = retries
                retryreq.dont_filter = True
                retryreq.priority = request.priority + self.priority_adjust
    
                if isinstance(reason, Exception):
                    reason = global_object_name(reason.__class__)
    
                stats.inc_value('retry/count')
                stats.inc_value('retry/reason_count/%s' % reason)
                return retryreq
            else:
                stats.inc_value('retry/max_reached')
                spider.logger.warn('超过重试次数,停止重试')
    

    process_response 方法主要是为了加一点 log process_exception 方法是为了出现任何 Exception 都能重试 同样,重写 _retry 方法也是为了加点 log

    我遇到的问题是,如果我 settings.py 中设定了 5 次重试,那么,log 中一定只打印第 6 次重试的 log,前 5 次的 log 并没有打出来,我很疑惑,求解答

    另外,我为了去除次数的问题,我还改配置改到 100 次,然而 log 中只打印第 101 次重试,然后就是 _retry 方法中的 else 语句的 log "超过重试次数,停止重试"

    8 条回复    2019-02-04 21:46:18 +08:00
    meik2333
        1
    meik2333  
       2019-02-04 00:09:24 +08:00 via Android
    现在手机没法调试代码,scrapy 的下载异常记得有两种情况来着:

    - 下载失败(超时等等)
    - 下载成功但状态码不对( 40x,50x 等等)

    process_exception 应该是下载失败才会触发(当然也有可能我记错了,好久不用了已经)
    meik2333
        2
    meik2333  
       2019-02-04 00:11:16 +08:00 via Android
    还有一个你 if 里面 logger 是 debug,else 里面是 warn,如果 settings 里面改了 log_level 的话可能会看不到。
    warcraft1236
        3
    warcraft1236  
    OP
       2019-02-04 09:38:29 +08:00
    @meik2333 if 里边的是 Scrapy 的代码,我没有改,但是经过你的提醒,我终于发现我确实看不到 log,因为我配置的 loglevel 是 warn,多谢
    warcraft1236
        4
    warcraft1236  
    OP
       2019-02-04 09:45:13 +08:00
    @meik2333 我发现,我爬取了一批视频,总是有几个下载报 403,然而我手动打开这个视频是正常的。 我有 headers 中 random UA 和 X-Forwarded-For,不知道是不是因为下载太多被封了
    meik2333
        5
    meik2333  
       2019-02-04 11:21:04 +08:00 via Android
    @warcraft1236 403 一般来说是触发反爬了
    warcraft1236
        6
    warcraft1236  
    OP
       2019-02-04 18:28:13 +08:00
    @meik2333 我重新试了一下,我上边这段代码确实打印不出来 if retries <= retry_times: 判断里边的 log

    重新看了一下,发现

    ```
    INFO: Enabled downloader middlewares:
    ['scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware',
    'New91Crawler.middlewares.CustomerRetryMiddleware',
    'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware',
    'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware',
    'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware',
    'scrapy.downloadermiddlewares.retry.RetryMiddleware',
    'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware',
    'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware',
    'scrapy.downloadermiddlewares.redirect.RedirectMiddleware',
    'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware',
    'scrapy.downloadermiddlewares.stats.DownloaderStats']

    ```

    我自定义的 retry 和 Scrapy 自带的 retry 都加载了,理论上不应该用我的覆盖系统的吗?
    meik2333
        7
    meik2333  
       2019-02-04 18:35:43 +08:00 via Android
    @warcraft1236 你可以看看 settings 里面的优先级,记得是数值越低的越先执行,系统自带的 retry 优先级好像是 550。

    我只知道如何让自己的先执行,如何覆盖掉确实不知道了。
    warcraft1236
        8
    warcraft1236  
    OP
       2019-02-04 21:46:18 +08:00
    @meik2333 我自己的是 200,但是感觉还是先走的系统的,重试了之后才走的我的,奇怪
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5699 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 02:08 · PVG 10:08 · LAX 19:08 · JFK 22:08
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.