我想异步查询数据库中的密钥,然后为每个密钥发出几个URL的请求。
我有一个函数从数据库中返回Deferred
,其值是多个请求的键。理想情况下,我会调用此函数并从start_requests
返回Deferreds的生成器。
@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):
????
但尝试以多种方式提出
builtins.AttributeError: 'Deferred' object has no attribute 'dont_filter'
我认为start_requests
必须返回Request
个对象,而不是返回值为Request
个对象的Deferreds。蜘蛛中间件process_start_requests()
似乎也是如此。
或者,我可以向http://localhost/
发出初始请求,并在通过下载程序中间件process_request()
从数据库获得密钥后将其更改为真实网址。但是,process_request
仅返回Request
个对象;它无法使用密钥向多个页面发出请求:尝试yield Request(url)
加注
AssertionError: Middleware myDownloaderMiddleware.process_request
must return None, Response or Request, got generator
最干净的解决方案是什么?
答案 0 :(得分:0)
您可以让Deferred对象的回调将url传递给某种类型的生成器。然后,生成器将任何收到的URL转换为scrapy Request对象并生成它们。下面是使用您链接的代码(未测试)的示例:
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
不要忘记在完成后停止请求生成器。
答案 1 :(得分:0)
您没有提供异步数据库查询的必要用例。我假设您不能开始刮取您的URL,除非您先查询数据库?如果是这种情况那么你最好只是同步进行查询,迭代查询结果,提取你需要的东西,然后产生Request
个对象。以异步方式查询数据库并等待查询完成是没有意义的。