5月31日 01:07

Scrapy 数据导出格式怎么选?JSON、CSV 和数据库如何取舍?

先说结论

Scrapy 内置的数据导出主要覆盖 JSON、JSON Lines、CSV、XML、Pickle、Marshal 等格式,日常项目里最常用的是 JSON Lines、CSV 和数据库写入。选择时不要只看“能不能导出”,更要看数据量、下游使用方式、是否需要断点续跑、字段是否稳定,以及失败后能不能快速恢复。小批量调试用 JSON 很顺手,几十万条以上更推荐 JSON Lines;给运营或分析同学交付表格时用 CSV;需要持续入库、去重和查询时,把导出交给 Item Pipeline 写 MySQL、PostgreSQL、MongoDB 或对象存储会更稳。

Scrapy 的 feed export 可以通过命令行直接完成:

bash
scrapy crawl book -O output.json scrapy crawl book -o output.jl scrapy crawl book -O output.csv

-O 会覆盖已有文件,适合定时任务每次生成完整结果;-o 会追加写入,适合临时补采,但也容易把重复数据混进去。线上任务里我更倾向显式配置 FEEDS,因为编码、字段顺序、是否覆盖、存储路径都能写清楚,避免不同同事用不同命令跑出不同文件。

python
FEEDS = { "exports/%(name)s-%(time)s.jl": { "format": "jsonlines", "encoding": "utf8", "overwrite": False, "fields": ["title", "url", "price"], } }

JSON 和 JSON Lines 怎么选

JSON 会把全部 item 组织成一个数组,文件看起来完整,适合几百条、几千条的结果检查,也方便直接发给接口调用方。但它的边界是很明显的:文件没写完时不是合法 JSON,爬虫中途挂掉可能留下半截内容,大文件被编辑器打开也容易卡死。

JSON Lines 是一行一个 JSON 对象,天然适合爬虫这种持续流式产出的场景。任务中断时,前面已经写入的行通常还能继续被处理;后续用 jq、Spark、Fluent Bit 或日志系统消费也更自然。取舍点在于它不如普通 JSON “一眼看起来规整”,给非技术同事交付时需要提前说明格式。

CSV、XML 和二进制格式适合什么场景

CSV 的优势是通用,Excel、BI 工具、数据分析脚本都能打开。坑也在这里:字段里有逗号、换行、引号时必须依赖正确转义;中文还要注意编码,必要时给 Excel 使用方导出 utf-8-sig。如果 item 的字段经常变化,CSV 会比 JSON Lines 更难维护,因为列顺序和缺失值会影响下游解析。

XML 现在用得少,但和一些老系统、政企接口或 Java 生态集成时仍然会遇到。Pickle、Marshal 更偏 Python 内部使用,不建议作为跨团队交付格式,因为可读性差,也不适合不可信数据交换。

什么时候不要只靠文件导出

如果爬虫每天运行、数据需要去重、要追踪更新时间,文件导出就不够了。此时可以在 Pipeline 中做校验、清洗、批量写库,并用唯一键控制重复数据。边界是 Pipeline 里的数据库操作不要每条都同步提交,否则吞吐会被数据库拖垮;更稳的做法是批量写入、失败重试,并把原始导出保留一份作为兜底。

追问

为什么大数据量更推荐 JSON Lines?

因为 JSON Lines 是流式追加,Scrapy 每产生一条 item 就能写一行,不必等全部结果结束后再形成完整数组。任务崩溃时,已经写出的行大多还能被后续脚本继续处理,这是普通 JSON 很难做到的。它的代价是文件不是一个单独 JSON 数组,下游如果只接受标准数组,需要再做一次转换。实际项目里,如果采集量超过几万条,我通常优先选 JSON Lines。

-o-O 的区别会带来什么坑?

-o 是追加写入,-O 是覆盖写入。调试时追加很方便,但定时任务里忘了清理旧文件,就会把昨天和今天的数据混在一起。覆盖又有另一个边界:如果你想保留历史结果,必须把文件名带上日期或批次号。生产环境最好把这个选择写进 FEEDS,不要依赖人工记命令。

CSV 导出时最容易踩哪里?

最常见的是字段里包含换行、逗号或引号,导致下游看起来像“列错位”。另一个坑是中文编码,Excel 在某些环境下打开 UTF-8 CSV 会乱码,需要考虑 utf-8-sig。CSV 适合字段稳定的扁平数据,不适合嵌套结构。遇到列表、字典、多个图片链接这类字段,JSON Lines 通常更省心。

什么时候应该写数据库而不是导出文件?

当你需要增量更新、去重、按条件查询或和业务系统联动时,就应该考虑数据库。文件更像交付物或中间结果,数据库才适合长期维护状态。取舍在于数据库会引入连接池、事务、索引和失败重试,复杂度明显更高。我的建议是保留一份原始 JSON Lines,再由 Pipeline 或离线任务入库,这样排查问题时有退路。

FEEDS 配置比命令行导出好在哪里?

命令行适合临时跑一次,FEEDS 适合团队协作和线上任务。它能固定格式、编码、字段顺序、覆盖策略和路径模板,减少“我本地能跑、你那边文件不一样”的问题。边界是配置写死后灵活性会差一点,多个环境可能需要不同路径。可以用环境变量或不同 settings 文件拆开,避免把测试路径带到生产。

标签:Scrapy