做出 scrapy.Request 确定性?

Making scrapy.Request deteministics?

这对我来说不是问题,我可以没有它生活,但我只是好奇这是否可能以及如何实现。

今天我了解到,scrapy.Request 不会按照开始的顺序完成。

伪代码示例:

class SomeSpider(scrapy.Spider):
    def parse(self, response):

        # get all ads(25) from ads list
        for ad in adList():
            add_url = findAddUrl()
            yield scrapy.Request(add_url, callback=self.parseAd)

        # go to next page
        if some_condition_OK:
             next_page_url = findNextpageUrl()
             yield scrapy.Request(next_page_url)
        else:
            print 'Stoped at.'

    def parseAd(self, response):
        field_1 = get_field_1()
        field_n = get_field_n()

        # save field_1 to field_n to sqlite DB

这是我编写的蜘蛛的简化示例,它运行良好。

但我今天了解到 yield scrapy.Request 不会按照开始的顺序完成。

在我的示例中,在每个页面上,每个页面有 25 个广告,我开始 yield scrapy.Request(add_url, callback=self.parseAd) 从每个广告中获取更多信息。
然后,我使用 yield scrapy.Request(next_page_url).
进入下一页 但是我注意到 page2 中的一些广告将在 page1 中的所有广告之前完成。
我明白为什么,我看到了这种方法的好处。

但我的问题是可以使 scrapy.Request 具有确定性吗?

我所说的确定性是指每个 scrapy.Request 将按照与开始时相同的顺序完成。

添加这些设置:

DOWNLOAD_DELAY

Default: 0

DOWNLOAD_DELAY = 0.25 # 250 毫秒延迟

但是scrapy还有一个自动设置下载延迟的功能叫做AutoThrottle。它会根据 Scrapy 服务器和您正在抓取的网站的负载自动设置延迟。这比设置任意延迟效果更好。

使 Scrapy 具有确定性的唯一方法是同时只产生一个请求,同时将其余请求保存在列表或队列中:

class SomeSpider(scrapy.Spider):

    pending_request = []

    def parse(self, response):

        # get all ads(25) from ads list
        for ad in adList():
            add_url = findAddUrl()
            self.pending_request.append(
                scrapy.Request(add_url, callback=self.parseAd))

        # go to next page
        if some_condition_OK:
             next_page_url = findNextpageUrl()
             self.pending_request.append(scrapy.Request(next_page_url))
        else:
            print 'Stoped at.'

        if self.pending_request:
            yield self.pending_request.pop(0)

    def parseAd(self, response):
        field_1 = get_field_1()
        field_n = get_field_n()

        if self.pending_request:
            yield self.pending_request.pop(0)