带有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 中的逻辑运算符