如何获取Python Scrapy请求队列的请求数?遇返回值异常问题
Scrapy请求队列计数异常问题解析
问题现象
- 调用
len(self.crawler.engine.slot.scheduler)始终返回0,无法获取当前队列请求数 - 读取
self.crawler.engine.slot.scheduler.stats._stats['scheduler/enqueued']得到的是持续递增的累计值(1、2…10),和预期中“队列初始值高、随爬取递减”的逻辑不符 - 开启翻页请求后,队列统计值持续递增,即使已配置
CONCURRENT_REQUESTS = 1
核心原因
len(scheduler)无效的本质
Scrapy的Scheduler类本身没有实现__len__魔法方法,直接对其调用len()会返回默认值0,这种方式根本无法获取当前待处理请求数。scheduler/enqueued是累计值而非剩余值
这个统计项记录的是爬虫启动以来所有入队请求的总数,包括已经处理完成的请求,因此只会持续递增,不会随请求处理而减少,和你需要的“当前队列剩余请求数”不是同一个概念。翻页请求重复入队
你在遍历每个quote的循环内部判断并生成翻页请求,导致同一个页面的next_page被重复入队多次(每个quote对应一次),直接造成累计入队数暴涨。
解决方法与修正代码
1. 正确获取当前队列剩余请求数
访问调度器内部的queue属性(默认调度器使用PriorityQueue),通过len(queue)获取剩余待处理请求数。注意这是内部属性,不同Scrapy版本或自定义调度器可能有差异。
2. 修正翻页请求逻辑
将翻页请求的判断与生成移到遍历quote的循环外部,避免重复入队。
修正后的代码
import scrapy class QuotesSpider(scrapy.Spider): name = "quotes_spider" start_urls = [ f"https://quotes.toscrape.com/page/{i}/" for i in range(1, 11) ] custom_settings = { "CONCURRENT_REQUESTS": 1 } def parse(self, response): # 获取当前队列剩余请求数 try: queue_size = len(self.crawler.engine.slot.scheduler.queue) except AttributeError: queue_size = "无法获取(调度器队列类型不支持)" # 用官方Stats API获取累计入队数,而非直接访问私有属性 total_enqueued = self.crawler.stats.get_value("scheduler/enqueued", 0) print(f"\n处理页面: {response.url}") print(f"当前队列剩余请求数: {queue_size}") print(f"累计入队请求数: {total_enqueued}\n") # 解析quote数据 for quote in response.css("div.quote"): yield { "text": quote.css("span.text::text").get(), "author": quote.css("small.author::text").get(), "tags": quote.css("div.tags a.tag::text").getall(), } # 翻页逻辑移到循环外,避免重复入队 next_page = response.css("li.next a::attr(href)").get() if next_page is not None: next_page = response.urljoin(next_page) yield scrapy.Request(next_page, callback=self.parse)
额外说明
- 不建议直接访问
scheduler.stats._stats这种私有属性,使用self.crawler.stats.get_value()是更规范的方式,兼容性更好。 - 如果使用第三方调度器(如RedisScheduler),队列属性名称可能不同,需要对应调整获取方式。
内容的提问来源于stack exchange,提问作者Aananda Giri
相关产品推荐
相关产品推荐

