【问题标题】:Scrapy throws error ReactorNotRestartable when runnning on AWS LambdaScrapy 在 AWS Lambda 上运行时抛出错误 ReactorNotRestartable
【发布时间】:2017-07-12 07:52:47
【问题描述】:

我已经部署了一个 scrapy 项目,它会在 lambda api 请求到来时进行抓取。

它在第一次 api 调用时运行良好,但后来它失败并抛出 ReactorNotRestartable 错误。

据我所知,AWS Lambda 生态系统并没有杀死进程,因此反应器仍然存在于内存中。

lambda日志错误如下:

Traceback (most recent call last):
File "/var/task/aws-lambda.py", line 42, in run_company_details_scrapy
process.start()
File "./lib/scrapy/crawler.py", line 280, in start
reactor.run(installSignalHandlers=False)  # blocking call
File "./lib/twisted/internet/base.py", line 1242, in run
self.startRunning(installSignalHandlers=installSignalHandlers)
File "./lib/twisted/internet/base.py", line 1222, in startRunning
ReactorBase.startRunning(self)
File "./lib/twisted/internet/base.py", line 730, in startRunning
raise error.ReactorNotRestartable()
ReactorNotRestartable

lambda 处理函数是:

def run_company_details_scrapy(event, context):
   process = CrawlerProcess()
   process.crawl(CompanyDetailsSpidySpider)
   process.start()

我有一个解决方法,通过在启动函数中插入一个标志来停止反应器

process.start(stop_after_crawl=False)

但问题是我必须等到 lambda 调用超时。

尝试了其他解决方案,但似乎都不起作用。谁能指导我如何解决这个问题。

【问题讨论】:

  • 嗯。 Lambda 重用您的 Python 进程来处理多个事件?你的处理程序必须同步完成?
  • @firefox 因为您将问题标记为已解决。你能描述一下你是如何使用钩针来解决你的问题的吗?
  • @firefox 我很难在aws lambda中运行scrapy ..你是如何创建你的zip文件的?我有一个ImportError: cannot import name 'etree'

标签: amazon-web-services lambda scrapy twisted aws-lambda


【解决方案1】:

最近也遇到了同样的问题,Crochet因为种种原因不想工作了。

最终我们选择了肮脏的解决方案:只需在 lambda 处理程序函数的末尾调用sys.exit(0)(或sys.exit(1),如果发现错误,而不是查看返回码 AFAICT)。这非常有效。

如果您打算从您的 Lambda 返回一个响应,这显然不好,但如果您使用的是 Scrapy,则数据可能已经通过您的 Pipelines 持久化,并使用调度程序作为触发你的 Lambda,所以不需要响应。

注意:您在 CloudWatch 中收到来自 AWS 的通知:

RequestId: xxxx Process exited before completing request 

【讨论】:

    【解决方案2】:

    我在 AWS lambda 上遇到错误 ReactorNotRestartable,在我找到这个解决方案之后

    默认情况下,scrapy 的异步特性不适用于 Cloud Functions,因为我们需要一种阻止爬取的方法,以防止函数提前返回并在进程之前终止实例终止。

    相反,我们可以使用scrapydo 以阻塞方式运行您现有的蜘蛛:

    import scrapy
    import scrapy.crawler as crawler
    rom scrapy.spiders import CrawlSpider
    import scrapydo
    
    scrapydo.setup()
    
    # your spider
    class QuotesSpider(scrapy.Spider):
        name = "quotes"
        start_urls = ['http://quotes.toscrape.com/tag/humor/']
    
        def parse(self, response):
            for quote in response.css('div.quote'):
                print(quote.css('span.text::text').extract_first())
    
    scrapydo.run_spider(QuotesSpider)

    【讨论】:

      【解决方案3】:

      您可以尝试使用https://pypi.python.org/pypi/crochet 来协调使用在 Lambda 控制的主线程的非主线程中运行的反应器。

      Crochet 将为您进行线程反应器初始化,并提供工具使您可以轻松地从主线程调用反应器线程中的代码(并获得结果)。

      这可能更符合 Lambda 对您的代码的期望。

      【讨论】:

      【解决方案4】:

      此问题并非 AWS Lambda 独有 - 请参阅 running a spider in a Celery task

      你可以试试ScrapyScript(披露:我写的)。它产生一个子进程来支持 Twisted reactor,阻塞直到所有提供的蜘蛛都完成,然后退出。它是用 Celery 编写的,但用例类似。

      在你的情况下,这应该有效:

      from scrapyscript import Job, Processor
      def run_company_details_scrapy(event, context):
          job = Job(CompanyDetailsSpidySpider())
          Processor().run(job)`
      

      【讨论】:

      • Twisted 和多处理的粗心组合会导致奇怪的难以调试的错误。例如 - stackoverflow.com/questions/42347121/… - ScrapyScript 能解决这些问题吗?
      • @jschnurr 我在 lambda “模块初始化错误:'twisted.internet.reactor'”上使用scrapy时遇到了一个不同的错误,我尝试了scrapyscript但没有成功。你对这个问题有什么想法吗?
      猜你喜欢
      • 2019-04-01
      • 2020-12-11
      • 1970-01-01
      • 1970-01-01
      • 2018-08-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-13
      相关资源
      最近更新 更多