Comando de administración personalizado de Django que ejecuta Scrapy: ¿Cómo incluir las opciones de Scrapy?

Quiero poder ejecutar el marco de rastreo web Scrapy desde Django. Scrapy en sí solo proporciona una herramienta de línea de comandos para ejecutar sus comandos, es decir, la herramienta no fue escrita intencionalmente para ser llamada desde un progtwig externo.

El usuario Mikhail Korobov encontró una buena solución , a saber, llamar a Scrapy desde un comando de administración personalizado de Django. Por conveniencia, repito su solución aquí:

 # -*- coding: utf-8 -*- # myapp/management/commands/scrapy.py from __future__ import absolute_import from django.core.management.base import BaseCommand class Command(BaseCommand): def run_from_argv(self, argv): self._argv = argv return super(Command, self).run_from_argv(argv) def handle(self, *args, **options): from scrapy.cmdline import execute execute(self._argv[1:]) 

En lugar de llamar, por ejemplo, scrapy crawl domain.com ahora puedo hacer python manage.py scrapy crawl domain.com desde un proyecto de Django. Sin embargo, las opciones de un comando de Scrapy no se analizan en absoluto. Si hago python manage.py scrapy crawl domain.com -o scraped_data.json -t json , solo obtengo la siguiente respuesta:

 Usage: manage.py scrapy [options] manage.py: error: no such option: -o 

Entonces, mi pregunta es, ¿cómo extender el comando de administración personalizado para adoptar las opciones de línea de comandos de Scrapy?

Desafortunadamente, la documentación de Django de esta parte no es muy extensa. También he leído la documentación del módulo optparse de Python, pero luego no fue más claro para mí. ¿Alguien puede ayudarme en este sentido? ¡Muchas gracias por adelantado!

Está bien, he encontrado una solución a mi problema. Es un poco feo pero funciona. Dado que el comando manage.py del proyecto Django no acepta las opciones de la línea de comandos de Scrapy, divido la cadena de opciones en dos argumentos que son aceptados por manage.py . Después de analizar con éxito, vuelvo a unir los dos argumentos y se los paso a Scrapy.

Es decir, en lugar de escribir.

 python manage.py scrapy crawl domain.com -o scraped_data.json -t json 

Puse espacios entre las opciones como esta

 python manage.py scrapy crawl domain.com - o scraped_data.json - t json 

Mi función de manejar se ve así:

 def handle(self, *args, **options): arguments = self._argv[1:] for arg in arguments: if arg in ('-', '--'): i = arguments.index(arg) new_arg = ''.join((arguments[i], arguments[i+1])) del arguments[i:i+2] arguments.insert(i, new_arg) from scrapy.cmdline import execute execute(arguments) 

Mientras tanto, Mikhail Korobov ha proporcionado la solución óptima. Mira aquí:

 # -*- coding: utf-8 -*- # myapp/management/commands/scrapy.py from __future__ import absolute_import from django.core.management.base import BaseCommand class Command(BaseCommand): def run_from_argv(self, argv): self._argv = argv self.execute() def handle(self, *args, **options): from scrapy.cmdline import execute execute(self._argv[1:]) 

Creo que realmente estás buscando la directriz 10 de las convenciones de syntax de argumento POSIX :

El argumento – debe ser aceptado como un delimitador que indica el final de las opciones. Los siguientes argumentos deben tratarse como operandos, incluso si comienzan con el carácter ‘-‘. El argumento – no debe usarse como una opción o como un operando.

El módulo optparse de Python se comporta de esta manera, incluso bajo Windows.

Puse el módulo de configuración de proyectos de scrapy en la lista de argumentos, por lo que puedo crear proyectos de scrapy separados en aplicaciones independientes:

 # /management/commands/scrapy.py from __future__ import absolute_import import os from django.core.management.base import BaseCommand class Command(BaseCommand): def handle(self, *args, **options): os.environ['SCRAPY_SETTINGS_MODULE'] = args[0] from scrapy.cmdline import execute # scrapy ignores args[0], requires a mutable seq execute(list(args)) 

Invocado de la siguiente manera:

 python manage.py scrapy myapp.scrapyproj.settings crawl domain.com -- -o scraped_data.json -t json 

Probado con scrapy 0.12 y django 1.3.1