bigywater.tech
Scrapy · 13

Item pipeline:process_item 的顺序与丢弃

item 从回调出来之后,管道按什么顺序处理?丢弃、报错、返回 None 各会发生什么?open_spider 是依次还是同时执行?这篇用三个带记录的管道实测。

3
管道 B 返回 None 后 item_scraped_count 的值(三个 item 都算抓取成功)
同时
三个管道的 open_spider / close_spider 的启动方式
5.13 → 0.11 s
50 个 await 0.1 s 的 item,CONCURRENT_ITEMS 1 → 100

顺序与改写

实测 · 本机执行输出
   1.    227 ms  A     process_item  item={'price': 5}
   2.    227 ms  B     process_item  item={'price': 5, 'via_A': True}
   3.    227 ms  C     process_item  item={'price': 5, 'via_A': True, 'via_B': True}
   4.    227 ms  A     process_item  item={'price': -1}
   5.    227 ms  B     process_item  item={'price': -1, 'via_A': True}
   6.    227 ms  A     process_item  item={'price': 7}
   7.    227 ms  B     process_item  item={'price': 7, 'via_A': True}
   8.    227 ms  C     process_item  item={'price': 7, 'via_A': True, 'via_B': True}
  stats:item_dropped_count=1, item_dropped_reasons_count/DropItem=1, item_scraped_count=2
  日志:[scrapy.core.scraper] WARNING: Dropped: price must be positive

process_item 按 ITEM_PIPELINES 的数字从小到大依次调用,每个管道的返回值就是下一个管道的输入。

丢弃与异常

实测 · 本机执行输出
   1.    169 ms  A     process_item  item={'price': 5}
   2.    169 ms  B     process_item  item={'price': 5, 'via_A': True}
   3.    169 ms  C     process_item  item={'price': 5, 'via_A': True, 'via_B': True}
   4.    170 ms  A     process_item  item={'price': -1}
   5.    170 ms  B     process_item  item={'price': -1, 'via_A': True}
   6.    171 ms  A     process_item  item={'price': 7}
   7.    172 ms  B     process_item  item={'price': 7, 'via_A': True}
   8.    172 ms  C     process_item  item={'price': 7, 'via_A': True, 'via_B': True}
  stats:item_scraped_count=2
  日志:[scrapy.core.scraper] ERROR: Error processing {'price': -1}

只有 DropItem 是正式的丢弃方式:后面的管道不再调用,WARNING 日志,统计 item_dropped_count。其它异常只记 ERROR,爬虫继续。

open_spider / close_spider

实测 · 本机执行输出
   1.    167 ms  A     open_spider 开始
   2.    167 ms  B     open_spider 开始
   3.    167 ms  C     open_spider 开始
   4.    268 ms  C     open_spider 结束
   5.    368 ms  B     open_spider 结束
   6.    468 ms  A     open_spider 结束
   7.    490 ms  C     close_spider 开始
   8.    490 ms  B     close_spider 开始
   9.    490 ms  A     close_spider 开始
  10.    591 ms  A     close_spider 结束
  11.    691 ms  B     close_spider 结束
  12.    791 ms  C     close_spider 结束

所有管道的 open_spider 同时开始、各自结束(asyncio 下用 gather),close_spider 同理。

返回 None

实测 · 本机执行输出
   1.    159 ms  A     process_item  item={'price': 5}
   2.    160 ms  B     process_item  item={'price': 5, 'via_A': True}
   3.    160 ms  C     process_item  item=None
   4.    160 ms  A     process_item  item={'price': -1}
   5.    160 ms  B     process_item  item={'price': -1, 'via_A': True}
   6.    160 ms  C     process_item  item=None
  stats:item_scraped_count=3
  日志:(没有 ERROR)

返回 None 并不会丢弃 item,下一个管道会收到 None,统计里仍算抓取成功。

并发

实测 · 本机执行输出
    CONCURRENT_ITEMS     总耗时 s    理想值 50×0.1/N
                   1      5.13            5.00   (item_scraped_count=50)
                  10      0.52            0.50   (item_scraped_count=50)
                 100      0.11            0.05   (item_scraped_count=50)

同一个回调产出的多个 item 在管道里并行处理,上限 CONCURRENT_ITEMS。管道用 async def 才能真正并行。

签名

实测 · 本机执行输出
  事件:[('旧签名被调用', 's')];item_scraped_count=1
  警告:Old.process_item() requires a spider argument, this is deprecated and the argument will not be passed in future Scrapy versions. If you need to access the spider instance

新签名是 process_item(self, item);旧的 (item, spider) 仍可用但会警告。

分步演示

item pipeline
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.8 / Scrapy 2.19.0 / Twisted 26.4.0 / lxml 6.1.3 / parsel 1.12.1(临时虚拟环境);所有请求只发给本机自己起的测试服务器(127.0.0.1,端口 9960 以上,不访问任何真实网站);服务器可以按实验需要制造延迟、重定向、压缩、断连等行为,并记录收到的原始请求;每个实验在临时目录里新建 Scrapy 项目或单文件 spider,命令输出来自真实的 scrapy 进程;计时用 time.perf_counter,数字每次运行会有小幅抖动。用工厂函数生成带记录的 async 管道,通过 custom_settings 的 ITEM_PIPELINES 加入;事件的毫秒数是 spider 进程内的相对时间
    • 没有验证:Feed 导出遇到 None item 的行为;ITEM_PROCESSOR 设置的自定义实现;process_item 返回 Deferred(旧写法)的兼容;管道里调用 crawler.engine.crawl 的行为;图片/文件管道(见后面的文章);item_error 信号的触发时机
    京ICP备2026067502号-1京公网安备11010502063487号