Scrapy – Reactor no reiniciable

con:

from twisted.internet import reactor from scrapy.crawler import CrawlerProcess 

Siempre he ejecutado este proceso con éxito:

 process = CrawlerProcess(get_project_settings()) process.crawl(*args) # the script will block here until the crawling is finished process.start() 

pero desde que moví este código a una función web_crawler(self) , así:

 def web_crawler(self): # set up a crawler process = CrawlerProcess(get_project_settings()) process.crawl(*args) # the script will block here until the crawling is finished process.start() # (...) return (result1, result2) 

y comencé a llamar al método utilizando la instanciación de clase, como:

 def __call__(self): results1 = test.web_crawler()[1] results2 = test.web_crawler()[0] 

y corriendo:

 test() 

Estoy teniendo el siguiente error:

 Traceback (most recent call last): File "test.py", line 573, in  print (test()) File "test.py", line 530, in __call__ artists = test.web_crawler() File "test.py", line 438, in web_crawler process.start() File "/Library/Python/2.7/site-packages/scrapy/crawler.py", line 280, in start reactor.run(installSignalHandlers=False) # blocking call File "/Library/Python/2.7/site-packages/twisted/internet/base.py", line 1194, in run self.startRunning(installSignalHandlers=installSignalHandlers) File "/Library/Python/2.7/site-packages/twisted/internet/base.py", line 1174, in startRunning ReactorBase.startRunning(self) File "/Library/Python/2.7/site-packages/twisted/internet/base.py", line 684, in startRunning raise error.ReactorNotRestartable() twisted.internet.error.ReactorNotRestartable 

¿qué está mal?

Related of "Scrapy – Reactor no reiniciable"

No puede reiniciar el reactor, pero debería poder ejecutarlo más veces realizando un proceso por separado:

 import scrapy import scrapy.crawler as crawler from multiprocessing import Process, Queue from twisted.internet import reactor # 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()) # the wrapper to make it run more times def run_spider(spider): def f(q): try: runner = crawler.CrawlerRunner() deferred = runner.crawl(spider) deferred.addBoth(lambda _: reactor.stop()) reactor.run() q.put(None) except Exception as e: q.put(e) q = Queue() p = Process(target=f, args=(q,)) p.start() result = q.get() p.join() if result is not None: raise result 

Ejecutar dos veces:

 print('first run:') run_spider(QuotesSpider) print('\nsecond run:') run_spider(QuotesSpider) 

Resultado:

 first run: “The person, be it gentleman or lady, who has not pleasure in a good novel, must be intolerably stupid.” “A day without sunshine is like, you know, night.” ... second run: “The person, be it gentleman or lady, who has not pleasure in a good novel, must be intolerably stupid.” “A day without sunshine is like, you know, night.” ... 

Esto es lo que me ayudó a ganar la batalla contra el error ReactorNotRestartable: última respuesta del autor de la pregunta.
0) pip install crochet
1) import from crochet import setup
2) setup() – en la parte superior del archivo
3) eliminar 2 líneas:
a) d.addBoth(lambda _: reactor.stop())
b) reactor.run()

Tuve el mismo problema con este error, y dediqué más de 4 horas a resolver este problema, lea todas las preguntas aquí. Finalmente encontré ese – y compartirlo. Así es como resolví esto. Las únicas líneas significativas de los documentos de Scrapy que quedan son las 2 últimas líneas en este mi código:

 #some more imports from crochet import setup setup() def run_spider(spiderName): module_name="first_scrapy.spiders.{}".format(spiderName) scrapy_var = import_module(module_name) #do some dynamic import of selected spider spiderObj=scrapy_var.mySpider() #get mySpider-object from spider module crawler = CrawlerRunner(get_project_settings()) #from Scrapy docs crawler.crawl(spiderObj) #from Scrapy docs 

Este código me permite seleccionar qué araña se ejecutará solo con su nombre pasado a la función run_spider y, una vez que finalice el desguace, seleccione otra araña y vuelva a ejecutarla.
Espero que esto ayude a alguien, como me ayudó a mí 🙂

Según la documentación de Scrapy , el método start() de la clase CrawlerProcess hace lo siguiente:

“[…] inicia un reactor retorcido, ajusta el tamaño de su grupo a REACTOR_THREADPOOL_MAXSIZE, e instala un caché de DNS basado en DNSCACHE_ENABLED y DNSCACHE_SIZE”.

El error que está recibiendo está siendo generado por Twisted , porque un reactor Twisted no se puede reiniciar. Utiliza una tonelada de globales, e incluso si haces jimmy-rig algún tipo de código para reiniciarlo (lo he visto hecho), no hay garantía de que funcione.

Honestamente, si crees que necesitas reiniciar el reactor, es probable que estés haciendo algo mal.

Dependiendo de lo que quieras hacer, también revisaría la Ejecución de Scrapy desde una parte de Script de la documentación, también.

El error está en este código:

 def __call__(self): result1 = test.web_crawler()[1] result2 = test.web_crawler()[0] # here 

web_crawler() devuelve dos resultados, y para ese propósito está intentando iniciar el proceso dos veces, reiniciando el Reactor, según lo señalado por @Rejected.

La obtención de resultados ejecutando un solo proceso, y el almacenamiento de ambos resultados en una tupla, es el camino a seguir aquí:

 def __call__(self): result1, result2 = test.web_crawler() 

Esto solucionó mi problema, pongo el código debajo de reactor.run() o process.start() :

 time.sleep(0.5) os.execl(sys.executable, sys.executable, *sys.argv) 

Como ya lo han señalado algunas personas: no es necesario reiniciar el reactor.

Lo ideal es que si desea encadenar sus procesos (crawl1 y crawl2 y crawl3) simplemente agregue devoluciones de llamada.

Por ejemplo, he estado usando esta araña de bucle que sigue este patrón:

 1. Crawl A 2. Sleep N 3. goto 1 

Y así es como se ve en scrapy:

 import time from scrapy.crawler import CrawlerRunner from scrapy.utils.project import get_project_settings from twisted.internet import reactor class HttpbinSpider(scrapy.Spider): name = 'httpbin' allowed_domains = ['httpbin.org'] start_urls = ['http://httpbin.org/ip'] def parse(self, response): print(response.body) def sleep(_, duration=5): print(f'sleeping for: {duration}') time.sleep(duration) # block here def crawl(runner): d = runner.crawl(HttpbinSpider) d.addBoth(sleep) d.addBoth(lambda _: crawl(runner)) return d def loop_crawl(): runner = CrawlerRunner(get_project_settings()) crawl(runner) reactor.run() if __name__ == '__main__': loop_crawl() 

Para explicar más el proceso, la función de crawl progtwig un rastreo y agrega dos devoluciones de llamada adicionales que se están realizando cuando se termina el rastreo: se bloquea el reposo y la llamada recursiva (progtwigr otro rastreo).

 $ python endless_crawl.py b'{\n "origin": "000.000.000.000"\n}\n' sleeping for: 5 b'{\n "origin": "000.000.000.000"\n}\n' sleeping for: 5 b'{\n "origin": "000.000.000.000"\n}\n' sleeping for: 5 b'{\n "origin": "000.000.000.000"\n}\n' sleeping for: 5