【问题标题】:Scrapy - set delay to retry middlewareScrapy - 设置延迟重试中间件
【发布时间】:2019-03-30 13:38:49
【问题描述】:

我正在使用Scrapy-splash,但我的内存有问题。我可以清楚地看到dockerpython3 使用的内存在逐渐增加,直到PC 死机。

无法弄清楚它为什么会这样,因为我有 CONCURRENT_REQUESTS=3 并且不可能 3 HTML 消耗 10GB RAM。

所以有一种解决方法可以将maxrss 设置为某个合理的值。当 RAM 使用率具有此值时,docker 会重新启动,因此 RAM 会被刷新。

但问题是,在docker 关闭期间,scrapy 继续发送请求,因此有几个urls 没有被删除。重试中间件正在尝试立即重试这些请求,然后放弃。

[scrapy.downloadermiddlewares.retry] DEBUG: Retrying <GET https://www.ex.com/eiB3t/ via http://127.0.0.1:8050/execute> (failed 2 times): [<twisted.python.failure.Failure twisted.internet.error.ConnectionDone: Connection was closed cleanly.>]
2019-03-30 14:28:33 [scrapy.downloadermiddlewares.retry] DEBUG: Gave up retrying <GET https://www.ex.com/eiB3t/

所以我有两个问题

  1. 您知道更好的解决方案吗?
  2. 如果没有,我如何在一段时间后将Scrapy 设置为retry 请求(假设是在分钟,所以docker 有时间重新启动)?

【问题讨论】:

    标签: python docker scrapy splash-screen


    【解决方案1】:

    一种方法是向您的 Spider 添加一个中间件(source、linked):

    # File: middlewares.py
    
    from twisted.internet import reactor
    from twisted.internet.defer import Deferred
    
    
    class DelayedRequestsMiddleware(object):
        def process_request(self, request, spider):
            delay_s = request.meta.get('delay_request_by', None)
            if not delay_s:
                return
    
            deferred = Deferred()
            reactor.callLater(delay_s, deferred.callback, None)
            return deferred
    

    你以后可以像这样在你的 Spider 中使用它:

    import scrapy
    
    
    class QuotesSpider(scrapy.Spider):
        name = "quotes"
        custom_settings = {
            'DOWNLOADER_MIDDLEWARES': {'middlewares.DelayedRequestsMiddleware': 123},
        }
    
        def start_requests(self):
            # This request will have itself delayed by 5 seconds
            yield scrapy.Request(url='http://quotes.toscrape.com/page/1/', 
                                 meta={'delay_request_by': 5})
            # This request will not be delayed
            yield scrapy.Request(url='http://quotes.toscrape.com/page/2/')
    
        def parse(self, response):
            ...  # Process results here
    

    相关方法在此描述:Method #2

    【讨论】:

      【解决方案2】:
      1. 更复杂的解决方案可能是设置一个运行多个副本的 Kubernetes 集群。这样您就可以避免仅 1 个容器发生故障而影响您的抓取工作。

      2. 我认为只为重试配置等待时间并不容易。您可以使用 DOWNLOAD_DELAY(但这会影响所有请求之间的延迟),或者将 RETRY_TIMES 设置为高于默认值 2 的值。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-04-08
        • 1970-01-01
        • 1970-01-01
        • 2015-01-31
        • 2019-10-29
        • 2012-06-09
        • 2020-06-28
        相关资源
        最近更新 更多