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()

要点说明:

  1. 缓冲区 (self.buffer):用来攒item,等数量够了再批量写。
  2. 批次刷写 (_flush_buffer):把缓冲区里的数据一次性写出去,然后清空缓冲区。
  3. 信号连接 (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 可以在这里导出

都是🐸,你看你都丑成啥样了。

谢谢大家,明白了,都怪自己没有细看官方文档。谢谢大家,学习成长了。

一样丑……

回到顶部