item 从回调出来之后,管道按什么顺序处理?丢弃、报错、返回 None 各会发生什么?open_spider 是依次还是同时执行?这篇用三个带记录的管道实测。
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 positiveprocess_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,爬虫继续。
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 同理。
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) 仍可用但会警告。