带有scrapy的while循环中的ReactorNotRestartable错误

Posted

技术标签:

【中文标题】带有scrapy的while循环中的ReactorNotRestartable错误【英文标题】:ReactorNotRestartable error in while loop with scrapy 【发布时间】:2017-02-18 04:30:31 【问题描述】:

执行以下代码时出现twisted.internet.error.ReactorNotRestartable 错误:

from time import sleep
from scrapy import signals
from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings
from scrapy.xlib.pydispatch import dispatcher

result = None

def set_result(item):
    result = item

while True:
    process = CrawlerProcess(get_project_settings())
    dispatcher.connect(set_result, signals.item_scraped)

    process.crawl('my_spider')
    process.start()

    if result:
        break
    sleep(3)

第一次工作,然后我得到错误。我每次都创建process变量,那有什么问题?

【问题讨论】:

【参考方案1】:

默认情况下,CrawlerProcess.start() 将在所有爬虫完成后停止它创建的 Twisted reactor。

如果您在每次迭代中创建process,您应该调用process.start(stop_after_crawl=False)

另一种选择是自己处理 Twisted reactor 并使用 CrawlerRunner。 The docs have an example 这样做。

【讨论】:

process.start(stop_after_crawl=False) — 将阻塞主进程 @Iliaw495Nikitin,CrawlerProcess.start() 将运行反应器并在抓取完成时将控制权交还给线程,正确。这是一个问题吗?替代scrapy.crawler.CrawlerRunner's .crawl() “返回一个在爬取完成时触发的延迟。” 阻塞对于 AWS Lambda 来说不是一个好主意,不是吗?我确实花了半天时间才弄清楚如何在 AWS Lambda 上运行它,但仍然一无所获。 我不知道 AWS Lambda 是如何工作的。您可能想发布一个新问题。【参考方案2】:

我能够像这样解决这个问题。 process.start() 只能调用一次。

from time import sleep
from scrapy import signals
from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings
from scrapy.xlib.pydispatch import dispatcher

result = None

def set_result(item):
    result = item

while True:
    process = CrawlerProcess(get_project_settings())
    dispatcher.connect(set_result, signals.item_scraped)

    process.crawl('my_spider')

process.start()

【讨论】:

【参考方案3】:

参考http://crawl.blog/scrapy-loop/

 import scrapy
 from scrapy.crawler import CrawlerProcess
 from scrapy.utils.project import get_project_settings     
 from twisted.internet import reactor
 from twisted.internet.task import deferLater

 def sleep(self, *args, seconds):
    """Non blocking sleep callback"""
    return deferLater(reactor, seconds, lambda: None)

 process = CrawlerProcess(get_project_settings())

 def _crawl(result, spider):
    deferred = process.crawl(spider)
    deferred.addCallback(lambda results: print('waiting 100 seconds before 
    restart...'))
    deferred.addCallback(sleep, seconds=100)
    deferred.addCallback(_crawl, spider)
    return deferred


_crawl(None, MySpider)
process.start()

【讨论】:

【参考方案4】:

我能够通过这个简单的代码使用包钩针来缓解这个问题,这个简单的代码基于 Christian Aichinger 对这个问题的副本Scrapy - Reactor not Restartable 的回答。 Spiders的初始化是在主线程中完成的,而特定的爬行是在不同的线程中完成的。我正在使用 Anaconda (Windows)。

import time
import scrapy
from scrapy.crawler import CrawlerRunner
from crochet import setup

class MySpider(scrapy.Spider):
    name = "MySpider"
    allowed_domains = ['httpbin.org']
    start_urls = ['http://httpbin.org/ip']

    def parse(self, response):
        print(response.text)
        for i in range(1,6):
            time.sleep(1)
            print("Spider "+str(self.name)+" waited "+str(i)+" seconds.")

def run_spider(number):
    crawler = CrawlerRunner()
    crawler.crawl(MySpider,name=str(number))

setup()
for i in range(1,6):
    time.sleep(1)
    print("Initialization of Spider #"+str(i))
    run_spider(i)

【讨论】:

【参考方案5】:

我在使用 Spyder 时遇到了类似的问题。从命令行运行文件而不是为我修复它。

Spyder 似乎第一次可以工作,但之后就不行了。也许反应堆保持打开而不关闭?

【讨论】:

【参考方案6】:

我可以建议你使用 subprocess 模块运行爬虫

from subprocess import Popen, PIPE

spider = Popen(["scrapy", "crawl", "spider_name", "-a", "argument=value"], stdout=PIPE)

spider.wait()

【讨论】:

【参考方案7】:

对于特定进程,一旦您调用 reactor.run() 或 process.start(),您将无法重新运行这些命令。原因是反应堆无法重新启动。一旦脚本完成执行,反应器将停止执行。

因此,如果您需要多次运行反应器,最好的选择是使用不同的子进程。

您可以将 while 循环的内容添加到函数中(例如 execute_crawling)。 然后,您可以使用不同的子进程简单地运行它。对于这个 python Process 模块可以使用。 代码如下。

from multiprocessing import Process
def execute_crawling():
    process = CrawlerProcess(get_project_settings())#same way can be done for Crawlrunner
    dispatcher.connect(set_result, signals.item_scraped)
    process.crawl('my_spider')
    process.start()

if __name__ == '__main__':
for k in range(Number_of_times_you_want):
    p = Process(target=execute_crawling)
    p.start()
    p.join() # this blocks until the process terminates

【讨论】:

【参考方案8】:

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

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

相反,我们可以使用`

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)

` 以阻塞方式运行现有的蜘蛛:

【讨论】:

以上是关于带有scrapy的while循环中的ReactorNotRestartable错误的主要内容,如果未能解决你的问题,请参考以下文章

使用scrapy进行while循环时出现ReactorNotRestartable错误

带有双条件和 || 的 While 循环Swift 中的逻辑运算符

Java——Reactor模式(转)

Java IO的Reactor模式

带有while循环的Recvall在python中的两个设备之间不起作用

高性能IO之Reactor模式