spider - scrapy python 3 tutorial
Base de datos de consulta asĂncrona para claves para usar en mĂșltiples solicitudes (2)
No ha proporcionado ningún caso de uso para que las consultas asincrónicas de la base de datos sean una necesidad. Supongo que no puede comenzar a raspar sus URL a menos que consulte primero la base de datos. Si ese es el caso, es mejor que solo haga la consulta de forma síncrona, itere sobre los resultados de la consulta, extraiga lo que necesita y luego Request
objetos de Request
. Tiene poco sentido consultar un archivo db de forma asincrónica y simplemente esperar que la consulta termine.
Quiero consultar asincrónicamente una base de datos para claves, luego realizar solicitudes a varias URL para cada clave.
Tengo una función que devuelve un Deferred
de la base de datos cuyo valor es la clave para varias solicitudes. Idealmente, llamaría a esta función y devolvería un generador de Deferreds desde start_requests
.
@inlineCallbacks
def get_request_deferred(self):
d = yield engine.execute(select([table])) # async
d.addCallback(make_url)
d.addCallback(Request)
return d
def start_requests(self):
????
Pero intentar esto de varias maneras plantea
builtins.AttributeError: ''Deferred'' object has no attribute ''dont_filter''
lo cual quiero decir que start_requests
debe devolver objetos Request
, no Deferreds cuyos valores son objetos Request
. Lo mismo parece ser cierto de process_start_requests()
middleware de spider.
Alternativamente, puedo hacer solicitudes iniciales a, por ejemplo, http://localhost/
y cambiarlas a la url real una vez que la clave esté disponible desde la base de datos a través del middleware del descargador, process_request()
. Sin embargo, process_request
solo devuelve un objeto Request
; no puede generar Solicitudes a varias páginas con la clave: intentar aumentar la yield Request(url)
aumenta
AssertionError: Middleware myDownloaderMiddleware.process_request
must return None, Response or Request, got generator
Cuál es la solución más limpia para
- obtener la clave asincrónicamente de la base de datos
- para cada clave, genera varias solicitudes
Puede dejar que la devolución de llamada para el objeto Diferido pase las URL a un generador de algún tipo. El generador convertirá las URL recibidas en objetos de Request scrapy y los cederá. A continuación se muestra un ejemplo con el código que ha vinculado (no probado):
import scrapy
from Queue import Queue
from pdb import set_trace as st
from twisted.internet.defer import Deferred, inlineCallbacks
class ExampleSpider(scrapy.Spider):
name = ''example''
def __init__(self):
self.urls = Queue()
self.stop = False
self.requests = request_generator()
self.deferred = deferred_generator()
def deferred_generator(self):
d = Deferred()
d.addCallback(self.deferred_callback)
yield d
def request_generator(self):
while not self.stop:
url = self.urls.get()
yield scrapy.Request(url=url, callback=self.parse)
def start_requests(self):
return self.requests.next()
def parse(self, response):
st()
# when you need to parse the next url from the callback
yield self.requests.next()
@static_method
def deferred_callback(url):
self.urls.put(url)
if no_more_urls():
self.stop = True
No olvide detener el generador de solicitudes cuando haya terminado.