Ejecutar una araña rasposa en una tarea de Apio


Esto ya no funciona, la API de scrapy ha cambiado.

Ahora la documentación presenta una forma de " Ejecutar Scrapy desde un script" pero obtengo el error ReactorNotRestartable.

Mi tarea:

from celery import Task

from twisted.internet import reactor

from scrapy.crawler import Crawler
from scrapy import log, signals
from scrapy.utils.project import get_project_settings

from .spiders import MySpider



class MyTask(Task):
    def run(self, *args, **kwargs):
        spider = MySpider
        settings = get_project_settings()
        crawler = Crawler(settings)
        crawler.signals.connect(reactor.stop, signal=signals.spider_closed)
        crawler.configure()
        crawler.crawl(spider)
        crawler.start()

        log.start()
        reactor.run()
Author: Community, 2014-03-01

4 answers

El reactor retorcido no se puede reiniciar. Una solución para esto es dejar que la bifurcación de tareas de apio tenga un nuevo proceso hijo para cada rastreo que desee ejecutar como se propone en el siguiente post:

Ejecutar arañas rasposas en una tarea de Apio

Esto evita el "problema del reactor no se puede reiniciar" utilizando el paquete multiprocesamiento. Pero el problema con esto es que la solución ahora está obsoleta con la última versión de apio debido al hecho de que en su lugar, se encuentra con otro problema en el que un proceso daemon no puede generar subprocesos. Así que para que la solución funcione, necesita bajar en la versión de apio.

Sí, y la API de scrapy ha cambiado. Pero con modificaciones menores (importar Crawler en lugar de CrawlerProcess). Puede hacer que la solución funcione bajando en la versión apio.

El problema del apio se puede encontrar aquí: Apio #1709

Aquí está mi script de rastreo actualizado que funciona con nuevas versiones de apio utilizando billar en lugar de multiprocesamiento:

from scrapy.crawler import Crawler
from scrapy.conf import settings
from myspider import MySpider
from scrapy import log, project
from twisted.internet import reactor
from billiard import Process
from scrapy.utils.project import get_project_settings

class UrlCrawlerScript(Process):
    def __init__(self, spider):
        Process.__init__(self)
        settings = get_project_settings()
        self.crawler = Crawler(settings)
        self.crawler.configure()
        self.crawler.signals.connect(reactor.stop, signal=signals.spider_closed)
        self.spider = spider

    def run(self):
        self.crawler.crawl(self.spider)
        self.crawler.start()
        reactor.run()

def run_spider(url):
    spider = MySpider(url)
    crawler = UrlCrawlerScript(spider)
    crawler.start()
    crawler.join()

Editar: Leyendo el número de apio #1709 sugieren que se utilice billar en lugar de multiprocesamiento para eliminar la limitación de subprocesos. En otras palabras, debemos probar billar y ver si funciona!

Editar 2: Sí, usando billar , mi guión funciona con la última versión de apio! Ver mi actualizado script.

 32
Author: Bj Blazkowicz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:02:46

El reactor Retorcido no se puede reiniciar, por lo que una vez que una araña termina de funcionar y crawler detiene el reactor implícitamente, ese trabajador es inútil.

Como se publicó en las respuestas a esa otra pregunta, todo lo que necesita hacer es matar al trabajador que ejecutó su araña y reemplazarla con una nueva, lo que evita que el reactor se inicie y se detenga más de una vez. Para hacer esto, simplemente establezca:

CELERYD_MAX_TASKS_PER_CHILD = 1

La desventaja es que no estás realmente usando el reactor retorcido para su máximo potencial y desperdicio de recursos ejecutando múltiples reactores, ya que un reactor puede ejecutar múltiples arañas a la vez en un solo proceso. Un mejor enfoque es ejecutar un reactor por trabajador (o incluso un reactor globalmente) y no dejar que crawler lo toque.

Estoy trabajando en esto para un proyecto muy similar, así que actualizaré este post si hago algún progreso.

 10
Author: Blender,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-04 11:09:42

Para evitar el error ReactorNotRestartable al ejecutar Scrapy en la cola de tareas de Apio he utilizado hilos. El mismo enfoque utilizado para ejecutar Twisted reactor varias veces en una aplicación. Scrapy también se utiliza Retorcido, por lo que podemos hacer de la misma manera.

Aquí está el código:

from threading import Thread
from scrapy.crawler import CrawlerProcess
import scrapy

class MySpider(scrapy.Spider):
    name = 'my_spider'


class MyCrawler:

    spider_settings = {}

    def run_crawler(self):

        process = CrawlerProcess(self.spider_settings)
        process.crawl(MySpider)
        Thread(target=process.start).start()

No se olvide de aumentar CELERYD_CONCURRENCY para apio.

CELERYD_CONCURRENCY = 10

Funciona bien para mí.

Esto no está bloqueando la ejecución del proceso, pero de todos modos la mejor práctica de scrapy es procesar datos en devoluciones de llamada. Sólo haz esto. camino:

for crawler in process.crawlers:
    crawler.spider.save_result_callback = some_callback
    crawler.spider.save_result_callback_params = some_callback_params

Thread(target=process.start).start()
 2
Author: Denis Cherniatev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-24 13:54:39

Diría que este enfoque es muy ineficiente si tiene muchas tareas que procesar. Debido a que el apio está roscado, ejecuta cada tarea dentro de su propio hilo. Digamos que con RabbitMQ como broker puedes pasar >10K q / s. Con apio esto podría causar potencialmente a 10K hilos de sobrecarga! Yo aconsejaría no usar apio aquí. En su lugar acceder al corredor directamente!

 -2
Author: aliowka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-05 09:04:00