在 settings 中配置了关闭爬虫的相关扩展:

CLOSESPIDER_TIMEOUT

CLOSESPIDER_ITEMCOUNT

CLOSESPIDER_PAGECOUNT

CLOSESPIDER_ERRORCOUNT

或者是在命令行运行 spider 时,用命令行参数进行了相关设置:

scrapy crawl xxxSpider -s CLOSESPIDER_ITEMCOUNT=10

scrapy crawl xxxSpider -s CLOSESPIDER_TIMEOUT=10

你会发现,爬虫并不会在爬取10个 item 之后或者是在 10秒之后停止,可以查到数据库中,可能有20几个 item 或者说设置为10秒,但直到几十秒才停止。

这是什么原因呢?

当触发 spider 关闭时,CLOSESPIDER_ITEMCOUNT 正好被定义,但由于 scrapy 的异步特性,它将完成对当前正在处理的所有 item 的爬取。因此,如果你想解析 2 个 item,但其实已经有 20 个 item 正在队列中等待处理了,那么爬虫也将完成所有 item的解析。

(参考: https://stackoverflow.com/questions/44006672/scrapy-closespider-itemcount-setting-not-working-as-expected?r=SearchResults

 

如果一定要在确定的 n 个 item 之后关闭爬虫,可以偿试下面三种方案:

方案1:将下载并行数量改为1个(CONCURRENT_REQUESTS=1),可以在爬取n个之后,比较准确地把爬虫关闭在n个item的位置,但可能还有多出1个item,因为关闭spider时,可能还有一个item正在处理。

方案2:在 pipeline 中的 process_item() 方法中,将还未处理的 item 抛出 DropItem 异常处理掉。这种方法就是最准确地,只收集了 个item后其他 DropItem 丢弃。 

    if self.maxItemCount != 0 and self.itemCount >= self.maxItemCount:
        raise DropItem("ClOSESPIDER_ITEMCOUNT limit reached - " + str(self.maxItemCount))
    else:
        pass

方案3:判断当前爬到的 item数量是不是达到了 CLOSESPIDER_ITEMCOUNT 配置的数目,如果达到配置的数量,就 raise CloseSpider() 异常来关闭爬虫。(这种方法也无法准备地达到只收取 n 个 item 的目的。CloseSpider() 异常抛出后,爬虫还是会继续处理完正在等待的业务。)

(方案3参考:https://stackoverflow.com/questions/44566184/scrapy-spider-not-terminating-with-use-of-closespider-extension/44585423?r=SearchResults#44585423

(CloseSpider()异常文档链接: https://doc.scrapy.org/en/latest/topics/exceptions.html#closespider

(DropItem() 异常文档链接: https://doc.scrapy.org/en/latest/topics/exceptions.html#DropItem

方案3 示例代码如下:

import scrapy
from scrapy.spiders import XMLFeedSpider
from scrapy.exceptions import CloseSpider
from myspiders.items import MySpiderItem

class MySpiderSpider(XMLFeedSpider):
    name = "myspiders"
    allowed_domains = {"www.mysource.com"}
    start_urls = [
        "https://www.mysource.com/source.xml"
        ]
    iterator = 'iternodes'
    itertag = 'item'
    item_count = 0

    @classmethod
    def from_crawler(cls, crawler):
        settings = crawler.settings
        return cls(settings)

    def __init__(self, settings):
        self.settings = settings

    def parse_node(self, response, node):
        if(self.settings['CLOSESPIDER_ITEMCOUNT'] and int(self.settings['CLOSESPIDER_ITEMCOUNT']) == self.item_count):
            raise CloseSpider('CLOSESPIDER_ITEMCOUNT limit reached - ' + str(self.settings['CLOSESPIDER_ITEMCOUNT']))
        else:
            self.item_count += 1
        id = node.xpath('id/text()').extract()
        title = node.xpath('title/text()').extract()
        item = MySpiderItem()
        item['id'] = id
        item['title'] = title

        return item

 

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐