Python中Scrapy批量写入数据时,数量不足如何优雅收尾?
请问:
我在 Pipelines 的__init__中设置了一个变量 AAA,代码里写着:
if len(AAA)> 500:
汇总写入一次数据;
AAA= []
请问:最后程序结束的时候,如果 AAA 不足 500,如何收尾。
Python中Scrapy批量写入数据时,数量不足如何优雅收尾?
8 回复
结束的时候还有一个函数(一时之间想不起名字
在Scrapy里处理批量写入时数据量不足的情况,核心思路是让pipeline自己管理一个缓冲区,并确保在爬虫结束时(spider_closed信号)强制将缓冲区里剩下的数据写出去。
这里给你一个处理CSV批量写入的完整示例,其他数据库(像MySQL、MongoDB)的逻辑也差不多,就是改一下_flush_buffer方法里的写入代码。
# pipelines.py
import csv
from scrapy import signals
from itemadapter import ItemAdapter
class BatchCsvPipeline:
def __init__(self, batch_size=100):
self.batch_size = batch_size
self.buffer = []
self.file = None
self.writer = None
@classmethod
def from_crawler(cls, crawler):
pipeline = cls(batch_size=crawler.settings.getint('BATCH_SIZE', 100))
# 关键:连接spider_closed信号
crawler.signals.connect(pipeline.spider_closed, signal=signals.spider_closed)
return pipeline
def open_spider(self, spider):
# 打开文件,初始化CSV writer
self.file = open(f'{spider.name}_output.csv', 'w', newline='', encoding='utf-8')
self.writer = None # 会在第一次收到item时根据字段名创建
def process_item(self, item, spider):
# 将item转为字典并加入缓冲区
item_dict = ItemAdapter(item).asdict()
self.buffer.append(item_dict)
# 如果达到批次大小,就刷写到文件
if len(self.buffer) >= self.batch_size:
self._flush_buffer()
return item
def _flush_buffer(self):
"""将缓冲区中的数据写入CSV文件"""
if not self.buffer:
return
# 如果是第一次写入,用缓冲区的第一个item的键作为CSV的列头
if self.writer is None:
fieldnames = self.buffer[0].keys()
self.writer = csv.DictWriter(self.file, fieldnames=fieldnames)
self.writer.writeheader()
# 写入所有缓冲的数据
self.writer.writerows(self.buffer)
self.buffer.clear() # 清空缓冲区
def spider_closed(self, spider):
"""爬虫关闭时,强制刷写缓冲区中剩余的数据"""
self._flush_buffer()
if self.file:
self.file.close()
要点说明:
- 缓冲区 (
self.buffer):用来攒item,等数量够了再批量写。 - 批次刷写 (
_flush_buffer):把缓冲区里的数据一次性写出去,然后清空缓冲区。 - 信号连接 (
spider_closed):这是关键。爬虫结束时(不管是因为没数据了还是主动关闭),Scrapy会发这个信号,我们的pipeline收到后就把缓冲区里剩下的那点数据(哪怕不够一个批次)写出去,做到“优雅收尾”。
怎么用:
在settings.py里启用这个pipeline,还可以设一下批次大小:
ITEM_PIPELINES = {
'your_project.pipelines.BatchCsvPipeline': 300,
}
BATCH_SIZE = 100 # 可选,默认就是100
一句话总结: 用缓冲区加spider_closed信号确保最后一批数据总能被写入。
判断一下当前时间,超过上次记录时间比如 1 分钟的话,即使不足 500 条也写入。算是最简单的 workaround 了。
就用一楼的那个,收尾的时候再写一次。closed 函数。
https://docs.scrapy.org/en/latest/topics/spiders.html#scrapy.spiders.Spider.closed
pipline 里有个 close_spider 可以在这里导出
都是🐸,你看你都丑成啥样了。
一样丑……


