
前言在爬虫运维、数据交接、离线分析、临时归档等场景中文件导出是高频需求。Scrapy 原生支持 JSON、CSV 等格式导出同时可借助第三方库实现 Excel、TXT 等格式输出。相比于数据库存储文件导出具备开箱即用、无需额外部署服务、查看便捷、轻量化等特点适合小规模数据、测试校验、临时任务、离线分发等场景。本文从原生命令行导出、自定义管道导出两大方向入手讲解 CSV、JSON、Excel、TXT 主流格式的实现方案覆盖字段排序、编码处理、中文乱码、追加写入、大文件拆分、分布式集群导出、多爬虫分流文件等生产场景所有代码兼容单机与 Scrapy-Redis 分布式架构可直接落地使用。参考文档Scrapy 内置 Feed 导出文档pandas 数据读写文档openpyxl Excel 操作文档一、环境准备1.1 依赖安装原生格式CSV/JSON无需额外依赖Excel 导出需安装第三方库所有节点统一执行bash运行# Excel 读写依赖推荐 openpyxl支持 xlsx 格式 pip install openpyxl pandas1.2 基础 Item 定义复用通用数据模型统一导出字段items.pypython运行import scrapy class ExportDataItem(scrapy.Item): title scrapy.Field() url scrapy.Field() category scrapy.Field() publish_time scrapy.Field() content scrapy.Field()1.3 基础爬虫示例编写测试爬虫用于验证导出效果spiders/export_spider.pypython运行import scrapy from export_demo.items import ExportDataItem class ExportSpider(scrapy.Spider): name export_spider allowed_domains [example.com] start_urls [https://example.com] def parse(self, response): # 模拟多条测试数据 data_list [ {title: 测试标题1, url: https://example.com/1, category: 资讯, publish_time: 2026-06-09, content: 测试内容1}, {title: 测试标题2, url: https://example.com/2, category: 资讯, publish_time: 2026-06-09, content: 测试内容2} ] for data in data_list: item ExportDataItem() item.update(data) yield item二、原生命令行导出快速使用适合临时场景Scrapy 内置 Feed Exporter无需编写代码通过启动命令即可直接导出文件上手最快适合调试、临时导出数据。2.1 CSV 格式导出CSV 通用性最强Excel、WPS、记事本均可打开是爬虫首选文件格式。2.1.1 基础命令bash运行# 导出为 CSV默认编码、字段顺序跟随 Item scrapy crawl export_spider -o data.csv2.1.2 解决中文乱码Windows 重点默认编码为utf-8Windows 系统用 Excel 打开会出现中文乱码指定编码为gbkbash运行# Linux/Mac 推荐 utf-8 scrapy crawl export_spider -o data.csv -s FEED_EXPORT_ENCODINGutf-8 # Windows Excel 打开无乱码使用 gbk scrapy crawl export_spider -o data.csv -s FEED_EXPORT_ENCODINGgbk2.1.3 追加写入默认覆盖文件原生命令默认每次启动都会清空原有文件如需增量追加在settings.py配置python运行# settings.py FEED_EXPORT_APPEND True2.2 JSON 格式导出JSON 格式结构化强适合程序二次解析、接口对接场景。2.2.1 基础导出命令bash运行# 标准 JSON 数组格式 scrapy crawl export_spider -o data.json -s FEED_EXPORT_ENCODINGutf-82.2.2 JSON Lines 格式推荐大文件JSON Lines 每行一条独立 JSON 对象避免大文件解析卡顿是爬虫主流 JSON 格式bash运行# 后缀 .jl 代表 JSON Lines scrapy crawl export_spider -o data.jl2.3 命令行通用配置补充在settings.py全局配置导出参数无需每次加命令参数python运行# 全局导出编码 FEED_EXPORT_ENCODING utf-8 # 开启文件追加写入 FEED_EXPORT_APPEND True # 导出字段顺序固定列顺序 FEED_EXPORT_FIELDS [title, url, category, publish_time, content]三、自定义管道导出灵活可控生产主流命令行导出功能有限无法实现复杂逻辑动态文件名、分文件、数据过滤、格式美化。自定义管道是工程化项目首选方案可深度定制导出规则。3.1 通用前置说明所有自定义管道均在pipelines.py中编写在settings.py启用python运行ITEM_PIPELINES { export_demo.pipelines.自定义管道名: 300, }四、实战一CSV 自定义管道支持动态文件名、编码控制、增量追加、数据过滤适配长期采集场景。4.1 CSV 管道完整代码python运行import csv import os from scrapy.utils.project import get_project_settings class CsvExportPipeline: def __init__(self): self.settings get_project_settings() # 导出文件路径与名称 self.file_path ./spider_data.csv self.encoding utf-8 self.file None self.writer None # 标记文件是否已写入表头 self.has_header False def open_spider(self, spider): 爬虫启动初始化文件流 # 判断文件是否存在不存在则需要写入表头 self.has_header os.path.exists(self.file_path) # 打开文件newline 避免 CSV 多余空行 self.file open(self.file_path, a, encodingself.encoding, newline) self.writer csv.DictWriter( self.file, fieldnames[title, url, category, publish_time, content] ) # 无文件则写入表头 if not self.has_header: self.writer.writeheader() def process_item(self, item, spider): 单条数据写入 # 简单数据过滤过滤空标题数据 if not item.get(title): return item # 字典方式写入一行 self.writer.writerow(dict(item)) return item def close_spider(self, spider): 爬虫关闭释放文件句柄 if self.file: self.file.close()4.2 核心特性增量追加使用a模式打开文件多次启动爬虫数据持续追加表头控制仅文件首次创建时写入表头避免重复表头空行处理newline解决 Windows 下 CSV 出现空白行问题数据过滤可在写入前增加业务过滤规则。五、实战二JSON 自定义管道分为标准 JSON、JSON Lines 两种实现支持格式化输出、增量写入。5.1 JSON Lines 管道推荐大文件每行一条 JSON读写效率高适合海量数据python运行import json class JsonLineExportPipeline: def __init__(self): self.file_path ./spider_data.jl self.encoding utf-8 self.file None def open_spider(self, spider): self.file open(self.file_path, a, encodingself.encoding) def process_item(self, item, spider): # 转为 JSON 字符串写入单行 line json.dumps(dict(item), ensure_asciiFalse) \n self.file.write(line) return item def close_spider(self, spider): if self.file: self.file.close()参数说明ensure_asciiFalse保留中文不转义为 Unicode 编码。5.2 标准 JSON 数组管道将所有数据整合为一个 JSON 数组适合小体量数据python运行import json class JsonArrayExportPipeline: def __init__(self): self.file_path ./spider_data.json self.encoding utf-8 self.data_list [] def process_item(self, item, spider): self.data_list.append(dict(item)) return item def close_spider(self, spider): # 爬虫结束一次性写入整个数组 with open(self.file_path, w, encodingself.encoding) as f: json.dump(self.data_list, f, ensure_asciiFalse, indent2)缺点数据全部存内存大数据量禁用。六、实战三Excel 导出管道xlsx 格式使用openpyxl实现 Excel 读写支持单元格格式、多工作表、动态命名办公场景最常用。6.1 Excel 基础管道代码python运行from openpyxl import Workbook, load_workbook import os class ExcelExportPipeline: def __init__(self): self.file_path ./spider_data.xlsx self.sheet_name 采集数据 self.wb None self.ws None # 表头字段 self.headers [标题, 链接, 分类, 发布时间, 内容] def open_spider(self, spider): # 判断文件是否存在存在则加载不存在则新建 if os.path.exists(self.file_path): self.wb load_workbook(self.file_path) self.ws self.wb[self.sheet_name] else: self.wb Workbook() self.ws self.wb.active self.ws.title self.sheet_name # 写入表头 self.ws.append(self.headers) def process_item(self, item, spider): # 按顺序组装行数据 row [ item.get(title, ), item.get(url, ), item.get(category, ), item.get(publish_time, ), item.get(content, ) ] self.ws.append(row) return item def close_spider(self, spider): # 保存文件 self.wb.save(self.file_path) self.wb.close()6.2 进阶按日期动态生成文件名每天生成独立 Excel 文件避免单文件过大便于按日期归档python运行from datetime import datetime from openpyxl import Workbook, load_workbook import os class ExcelDatePipeline: def __init__(self): # 按日期命名文件2026-06-09_data.xlsx date_str datetime.now().strftime(%Y-%m-%d) self.file_path f./{date_str}_data.xlsx self.sheet_name 采集数据 self.headers [标题, 链接, 分类, 发布时间, 内容] self.wb None self.ws None def open_spider(self, spider): if os.path.exists(self.file_path): self.wb load_workbook(self.file_path) self.ws self.wb[self.sheet_name] else: self.wb Workbook() self.ws self.wb.active self.ws.title self.sheet_name self.ws.append(self.headers) def process_item(self, item, spider): row [item.get(k, ) for k in [title, url, category, publish_time, content]] self.ws.append(row) return item def close_spider(self, spider): self.wb.save(self.file_path) self.wb.close()七、实战四TXT 纯文本导出用于日志归档、简单文本记录格式自由灵活python运行class TxtExportPipeline: def __init__(self): self.file_path ./spider_data.txt self.encoding utf-8 self.file None def open_spider(self, spider): self.file open(self.file_path, a, encodingself.encoding) def process_item(self, item, spider): # 自定义文本格式 text f标题{item.get(title)} | 链接{item.get(url)} | 分类{item.get(category)}\n self.file.write(text) return item def close_spider(self, spider): if self.file: self.file.close()八、多爬虫分流导出多 Spider 专属文件前文多 Spider 架构中不同品类爬虫需要导出到独立文件通过spider.name判断爬虫名称实现文件分流。8.1 分流 CSV 管道示例python运行import csv import os class MultiSpiderCsvPipeline: def __init__(self): self.file_map {} self.encoding utf-8 self.fields [title, url, category, publish_time, content] def open_spider(self, spider): # 每个爬虫对应独立文件 file_name f{spider.name}_data.csv file_path f./{file_name} has_header os.path.exists(file_path) f open(file_path, a, encodingself.encoding, newline) writer csv.DictWriter(f, fieldnamesself.fields) if not has_header: writer.writeheader() self.file_map[spider.name] (f, writer) def process_item(self, item, spider): f, writer self.file_map.get(spider.name) writer.writerow(dict(item)) return item def close_spider(self, spider): f, _ self.file_map.get(spider.name) f.close()运行后不同 Spider 会生成digital_spider_data.csv、clothes_spider_data.csv等独立文件。九、分布式集群导出适配Scrapy-Redis9.1 核心问题多节点同时导出同一个文件会出现文件抢占、内容错乱、文件损坏。9.2 三种解决方案按场景选择方案 1各节点独立导出推荐每个爬虫节点生成本地文件后续统一合并。 实现沿用普通管道无需修改多节点各自生成data.csv任务完成后手动合并文件。方案 2指定单一导出节点管控型集群仅允许其中一台节点开启导出管道其余节点关闭全局只生成一份文件。python运行# 仅在导出节点的 settings.py 启用管道其他节点注释 ITEM_PIPELINES { export_demo.pipelines.CsvExportPipeline: 300, }方案 3Redis 中转高可靠爬虫节点不直接写文件数据推送至 Redis 列表单独启动消费脚本统一导出彻底规避文件冲突。十、大文件拆分策略单文件数据量过大超 10 万行会导致打开、读写缓慢按数据行数自动拆分文件python运行import csv import os class SplitCsvPipeline: def __init__(self): self.base_name split_data self.encoding utf-8 self.fields [title, url, category, publish_time, content] self.max_row 5000 # 每5000行拆分一个文件 self.current_row 0 self.file_index 1 self.file None self.writer None def create_new_file(self): 创建新文件 file_path f{self.base_name}_{self.file_index}.csv self.file open(file_path, w, encodingself.encoding, newline) self.writer csv.DictWriter(self.file, fieldnamesself.fields) self.writer.writeheader() def open_spider(self, spider): self.create_new_file() def process_item(self, item, spider): self.writer.writerow(dict(item)) self.current_row 1 # 达到行数阈值新建文件 if self.current_row self.max_row: self.file.close() self.file_index 1 self.current_row 0 self.create_new_file() return item def close_spider(self, spider): if self.file: self.file.close()十一、常见问题与解决方案11.1 中文乱码CSV/JSON统一设置encodingutf-8Windows Excel 打开 CSV 改用gbkExcelopenpyxl 原生支持中文一般无乱码。11.2 CSV 出现空白行原因Windows 换行符问题。解决打开文件时添加newline。11.3 多次启动文件内容被覆盖解决文件打开模式改为a追加模式。11.4 Excel 文件损坏、无法打开原因未正常关闭文件句柄、多进程同时写入。解决爬虫结束必须save()close()分布式避免多节点同写一个 Excel。11.5 字段顺序混乱解决手动指定fieldnames字段列表固定列顺序。十二、生产环境最佳实践格式选型规范临时查看、办公使用CSV / Excel程序二次解析、接口对接JSON Lines简单日志记录TXT。文件目录管理按日期、品类创建子目录分类存放文件避免根目录文件堆积。文件生命周期配置定时任务归档历史文件、删除过期文件释放磁盘空间。分布式规范优先使用「节点独立导出 后期合并」不建议多节点并发写入同一文件。数据校验导出后增加行数统计、关键字校验确保数据完整。超大文件严格启用按行拆分策略单文件行数控制在 2~5 万行以内。十三、结语文件导出是爬虫数据落地的重要分支本文覆盖了 Scrapy 从原生命令行到自定义管道、从基础格式到高级拆分、单机到分布式、单爬虫到多爬虫分流的全场景实现。CSV、JSON、Excel 三大主流格式可根据业务灵活搭配和之前讲解的 MySQL 入库、异常中间件、分布式调度、多 Spider 架构完全兼容可自由组合搭建一体化爬虫系统。