Cómo pasar un argumento definido por el usuario en scrapy spider

100

Estoy tratando de pasar un argumento definido por el usuario a una araña de scrapy. ¿Alguien puede sugerir cómo hacer eso?

Leí sobre un parámetro en -aalguna parte, pero no tengo idea de cómo usarlo.

L Lawliet
fuente

Respuestas:

188

Los argumentos de araña se pasan en el crawlcomando usando la -aopción. Por ejemplo:

scrapy crawl myspider -a category=electronics -a domain=system

Las arañas pueden acceder a los argumentos como atributos:

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

    def __init__(self, category='', **kwargs):
        self.start_urls = [f'http://www.example.com/{category}']  # py36
        super().__init__(**kwargs)  # python3

    def parse(self, response)
        self.log(self.domain)  # system

Tomado del documento Scrapy: http://doc.scrapy.org/en/latest/topics/spiders.html#spider-arguments

Actualización 2013 : agregar un segundo argumento

Actualización 2015 : ajustar la redacción

Actualización 2016 : use una clase base más nueva y agregue super, gracias @Birla

Actualización 2017 : use Python3 super

# previously
super(MySpider, self).__init__(**kwargs)  # python2

Actualización 2018 : como señala @eLRuLL , las arañas pueden acceder a argumentos como atributos

Steven Almeroth
fuente
3
scrapy crawl myspider -a categoría = electrónica -a dominio = sistema
Steven Almeroth
1
El código anterior solo funciona parcialmente para mí. Por ej. Si defino el uso de dominio self.domain, todavía no puedo acceder a él fuera del __init__método. Python arroja un error no definido. Por cierto, ¿por qué omitiste la superllamada? PD. Estoy trabajando con la clase CrawlSpider
Birla
2
@FlyingAtom Por favor corríjame si no entendí bien, pero cada una de estas llamadas simultáneas serían instancias diferentes de la araña, ¿no es así?
L Lawliet
1
@Birla, use self.domain = domain en el constructor para completar la variable de alcance de clase.
Hassan Raza
1
@nealmcb __init__es un método de la clase araña. Su implementación no hace que la araña sea menos robusta y se incluye en la respuesta para mostrar que puede declarar valores predeterminados para los argumentos de palabras clave, pero como dijo, es opcional. Como señalamos el año pasado, no necesita usar getattr, solo puede acceder a los argumentos como atributos, por ejemplo, self.categoryo como vemos en la respuestaself.domain
Steven Almeroth
31

Las respuestas anteriores eran correctas, pero no tiene que declarar el constructor ( __init__) cada vez que quiera codificar una araña de scrapy, simplemente puede especificar los parámetros como antes:

scrapy crawl myspider -a parameter1=value1 -a parameter2=value2

y en su código de araña puede usarlos como argumentos de araña:

class MySpider(Spider):
    name = 'myspider'
    ...
    def parse(self, response):
        ...
        if self.parameter1 == value1:
            # this is True

        # or also
        if getattr(self, parameter2) == value2:
            # this is also True

Y simplemente funciona.

eLRuLL
fuente
4
Cierto. Entra en el lado oscuro de Python.
Barney
14

Para pasar argumentos con el comando de rastreo

scrapy crawl myspider -a category = 'mycategory' -a domain = 'example.com'

Para pasar argumentos para que se ejecuten en scrapyd, reemplace -a con -d

curl http://your.ip.address.here:port/schedule.json -d spider = myspider -d category = 'mycategory' -d domain = 'example.com'

La araña recibirá argumentos en su constructor.


class MySpider(Spider):
    name="myspider"
    def __init__(self,category='',domain='', *args,**kwargs):
        super(MySpider, self).__init__(*args, **kwargs)
        self.category = category
        self.domain = domain

Scrapy pone todos los argumentos como atributos de araña y puede omitir el método init por completo. Tenga cuidado con el método getattr para obtener esos atributos para que su código no se rompa.


class MySpider(Spider):
    name="myspider"
    start_urls = ('https://httpbin.org/ip',)

    def parse(self,response):
        print getattr(self,'category','')
        print getattr(self,'domain','')
Hassan Raza
fuente
¡Sucinto, robusto y flexible!
nealmcb
8

Los argumentos Spider se pasan mientras se ejecuta el comando crawl usando la opción -a. Por ejemplo, si quiero pasar un nombre de dominio como argumento a mi araña, haré esto-

scrapy crawl myspider -a dominio = "http://www.example.com"

Y recibe argumentos en los constructores de spider:

class MySpider(BaseSpider):
    name = 'myspider'
    def __init__(self, domain='', *args, **kwargs):
        super(MySpider, self).__init__(*args, **kwargs)
        self.start_urls = [domain]
        #

...

funcionará :)

Siyaram Malav
fuente
0

Alternativamente, podemos usar ScrapyD que expone una API donde podemos pasar el start_url y el nombre de la araña. ScrapyD tiene api para detener / iniciar / estado / listar las arañas.

pip install scrapyd scrapyd-deploy
scrapyd
scrapyd-deploy local -p default

scrapyd-deploydesplegará la araña en forma de huevo en el demonio e incluso mantendrá la versión de la araña. Al iniciar la araña, puede mencionar qué versión de la araña usar.

class MySpider(CrawlSpider):

    def __init__(self, start_urls, *args, **kwargs):
        self.start_urls = start_urls.split('|')
        super().__init__(*args, **kwargs)
    name = testspider

curl http://localhost:6800/schedule.json -d project=default -d spider=testspider -d start_urls="https://www.anyurl...|https://www.anyurl2"

La ventaja adicional es que puede crear su propia interfaz de usuario para aceptar la URL y otros parámetros del usuario y programar una tarea utilizando la API de programación eliminada anterior

Consulte la documentación de la API scrapyd para obtener más detalles

Nagendran
fuente