You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scrapy技术问询:写入前检查CSV文件中的条目标题是否存在

我明白你要解决的核心问题——想让Scrapy爬虫只往CSV里写入标题不存在的条目,而且现成的DuplicatesPipeline对你不适用。咱们来把你的自定义Pipeline补全并优化,确保它能稳定工作。

问题分析

你之前的代码只完成了读取CSV的开头部分,缺少了存储已有标题、检查重复和写入新条目的核心逻辑。另外直接用open操作文件时,还要注意编码、文件不存在的异常处理,以及爬虫结束时的文件关闭操作。

完整的自定义Pipeline代码

下面是补全后的CheckCsvPipeline,我会逐段解释关键细节:

import csv
from scrapy.exceptions import DropItem

class CheckCsvPipeline(object):
    def __init__(self):
        # 你的CSV文件路径
        self.csv_path = r"C:\Users\HP\PycharmProjects\ToScrape\book\items.csv"
        # 用集合存储已有标题(集合的成员检查速度远快于列表)
        self.existing_titles = set()
        
        # 读取已有CSV,收集所有标题
        try:
            with open(self.csv_path, 'r', newline='', encoding='utf-8') as csvfile:
                # 用DictReader按字段名读取,不用关心列顺序
                reader = csv.DictReader(csvfile)
                # 这里假设你的CSV中标题列的字段名是'title',请根据实际情况修改
                for row in reader:
                    title = row.get('title', '').strip()
                    if title:
                        self.existing_titles.add(title)
        except FileNotFoundError:
            # 如果文件不存在,初始化空集合即可
            pass
        
        # 打开文件准备写入(用追加模式'a',保留原有内容)
        self.csvfile = open(self.csv_path, 'a', newline='', encoding='utf-8')
        # 定义CSV的字段名,要和你的Item类字段完全对应
        self.fieldnames = ['title', 'price', 'rating', 'stock']  # 替换成你实际的字段
        self.writer = csv.DictWriter(self.csvfile, fieldnames=self.fieldnames)
        
        # 如果是新创建的文件(集合为空),写入表头
        if not self.existing_titles:
            self.writer.writeheader()

    def process_item(self, item, spider):
        # 获取当前条目的标题,做去空格处理避免因空格导致的误判
        item_title = item.get('title', '').strip()
        
        if not item_title:
            # 如果标题为空,直接丢弃条目
            raise DropItem("Item has empty title")
        
        if item_title not in self.existing_titles:
            # 标题不存在,写入CSV并更新集合
            self.writer.writerow(item)
            self.existing_titles.add(item_title)
            spider.logger.info(f"✅ Added new item: {item_title}")
        else:
            # 标题已存在,丢弃重复条目
            raise DropItem(f"❌ Skipping duplicate item: {item_title}")
        
        return item

    def close_spider(self, spider):
        # 爬虫结束时关闭文件,确保所有写入操作生效
        self.csvfile.close()
        spider.logger.info("Pipeline closed, CSV file saved.")

关键细节说明

  1. 用集合存储标题:集合的in操作是O(1)时间复杂度,比列表的O(n)快得多,爬虫数据量大时优势明显。
  2. 异常处理:处理文件不存在的情况,避免爬虫启动时报错。
  3. 编码与换行符:指定encoding='utf-8'避免中文乱码,newline=''让CSV模块自动处理换行符,兼容不同系统。
  4. 字段名匹配:fieldnames必须和你的Scrapy Item类中的字段完全一致,否则写入会丢失数据。
  5. 日志输出:通过spider.logger打印操作日志,方便调试和查看去重情况。

启用Pipeline

最后别忘了在settings.py中启用这个Pipeline:

ITEM_PIPELINES = {
    'book.pipelines.CheckCsvPipeline': 300,  # 优先级数字越小越先执行
}

内容的提问来源于stack exchange,提问作者Land Owner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 02:27:42