用于多个请求的密钥的异步查询数据库

时间:2017-07-11 06:02:00

标签: python database asynchronous scrapy twisted

我想异步查询数据库中的密钥,然后为每个密钥发出几个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

最干净的解决方案是什么?
  • 从数据库中异步获取密钥
  • 为每个密钥生成多个请求

2 个答案:

答案 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个对象。以异步方式查询数据库并等待查询完成是没有意义的。