Python 爬虫项目:CSV 文件数据持久化
2026/6/11 16:08:42 网站建设 项目流程

前言

在爬虫工程化开发流程中,纯文本文件仅能满足简易数据归档需求,当采集数据具备多字段结构化特征、需要后续进行筛选、排序、统计、表格查看等操作时,文本格式的局限性便会凸显。CSV 作为通用的逗号分隔值文件格式,凭借轻量、跨软件兼容、解析高效、无需额外部署服务等特性,成为中小规模爬虫项目首选的结构化数据持久化方案。

CSV 文件可直接使用 Office Excel、WPS、记事本、各类代码编辑器打开查看与编辑,同时主流编程语言、数据分析工具均提供成熟的读写接口,能够无缝对接数据清洗、可视化、二次分析等后续流程。相较于传统 TXT 文本,CSV 天然支持行列结构划分,完美适配爬虫场景中列表嵌套字典的标准化数据格式,可清晰区分标题、时间、链接、内容等不同字段。

本文基于 Python 内置csv标准库与第三方高性能拓展库,结合前文分页爬虫、数据采集案例,系统讲解 CSV 文件的创建、单行 / 多行写入、表头定义、数据追加、文件读取、编码兼容、大文件处理、异常防护等全流程实战内容,同时拆解底层运行原理、不同写法的优劣对比以及爬虫场景下的落地规范,帮助开发者掌握工业级 CSV 数据持久化技术。

本文开发运行依赖库及官方地址如下:

  1. csv(Python 内置 CSV 读写标准库):Python 标准库,无需额外安装
  2. os(内置路径处理库):Python 标准库,无需额外安装
  3. time(内置时间工具库):Python 标准库,无需额外安装
  4. requests(网络请求库):https://pypi.org/project/requests/
  5. bs4(BeautifulSoup)(网页解析库):https://pypi.org/project/beautifulsoup4/
  6. lxml(HTML 解析引擎):https://pypi.org/project/lxml/

一、CSV 文件基础认知

1.1 CSV 格式规范与特性

CSV 全称 Comma-Separated Values,即逗号分隔值文件,其本质是一种纯文本格式文件,使用英文逗号作为字段分隔符,换行符作为行分隔符。每一行代表一条完整数据,每一个被逗号分割的片段对应一个独立字段。

标准 CSV 文件分为表头行与数据行两大结构:表头行位于文件首行,用于定义每一列的字段名称,例如标题、发布时间、作者、链接;数据行紧随表头之后,按列顺序填充对应数据。该结构与数据库表、Excel 表格逻辑完全一致,也是其具备高兼容性的核心原因。

从爬虫应用角度总结 CSV 核心特性:文件体积小、读写速度快、占用系统资源低;支持跨平台、跨软件打开编辑;原生支持结构化行列数据,适配爬虫主流数据结构;纯文本存储,不存在格式错乱问题。其短板为不支持复杂单元格格式、大数据量下查询效率弱于专业数据库,适合十万条以内中小规模数据存储。

1.2 Python csv 库核心组件说明

Python 内置csv库是操作 CSV 文件的原生工具,无需 pip 安装,库中封装了多个核心类与方法,适配不同读写场景,结合爬虫使用频率,核心组件分类说明如下表:

表格

核心组件功能作用适用场景
writer基础写入器,按行写入列表类型数据单行、批量多行简单数据写入
DictWriter字典写入器,按字段映射写入字典数据爬虫字典格式结构化数据写入(主流)
reader基础读取器,按行读取数据并转为列表读取简单无表头 CSV 文件
DictReader字典读取器,结合表头将数据转为字典读取带表头的标准结构化 CSV 文件(主流)

在爬虫项目中,采集后的数据大多以字典、列表嵌套字典形式存在,因此DictWriter 与 DictReader是使用频率最高的两个组件,也是本文重点讲解内容。

1.3 编码与换行符适配规则

中文乱码是 CSV 操作的高频问题,不同软件对 CSV 默认编码存在差异。Windows 系统下 Excel 打开 UTF-8 编码 CSV 文件易出现乱码,而记事本、代码编辑器、Linux/macOS 系统默认兼容 UTF-8。行业通用解决方案为:创建文件时指定encoding="utf-8-sig",该编码格式会在文件头部添加 BOM 标记,完美兼容 Windows 平台 Excel 软件,同时不影响其他编辑器正常读取。

换行符方面,csv库内部已封装换行处理逻辑,代码中无需手动添加\n,可直接规避不同系统换行符不统一导致的格式错乱问题。

二、基础写入实战:创建 CSV 与表头设置

2.1 writer 基础写入(列表数据)

2.1.1 场景分析

csv.writer适用于数据为一维列表、二维列表的简单场景,不依赖字段名映射,按照列表元素顺序依次写入单元格。该写法逻辑简单,适合无固定表头、临时数据存储场景。结合with上下文管理器实现文件自动关闭,保证资源安全释放。

2.1.2 单行数据写入代码实现

python

运行

import csv # 定义文件存储路径 csv_path = "./simple_data.csv" # 单行列表数据,对应一行多列内容 single_row = ["Python爬虫", "CSV持久化", "2026-06-11", "技术教程"] # 打开文件并创建写入器 with open(csv_path, mode="w", encoding="utf-8-sig", newline="") as f: # 初始化csv写入对象 writer = csv.writer(f) # 写入单行数据 writer.writerow(single_row) print("单行列表数据写入完成")
2.1.3 代码原理解析
  1. newline="" 参数作用文件打开参数中newline=""是 CSV 操作的标准配置。Python 在 Windows 系统下默认会自动补充换行符,若不设置该参数,写入后 CSV 文件会出现空行,破坏表格结构。该参数可屏蔽系统自动换行逻辑,保证文件格式整洁。

  2. writerow () 方法原理writerow()接收一维列表作为参数,会自动将列表内元素用英文逗号分隔,拼接为标准 CSV 行文本并写入文件,开发者无需手动处理分隔符,降低格式出错概率。

  3. 编码规则encoding="utf-8-sig"为爬虫 CSV 存储通用编码,兼顾中文显示与 Excel 兼容性,是项目开发中的强制规范。

2.1.4 多行数据写入代码实现

当存在多条数据时,使用writerows()方法可一次性写入二维列表,相较于循环调用writerow()执行效率更高,适合批量数据落地。

python

运行

import csv csv_path = "./multi_simple_data.csv" # 二维列表,外层代表行,内层代表列 multi_rows = [ ["分页抓取", "文本存储", "CSV存储"], ["Excel写入", "延时设置", "异常重试"], ["爬虫实战", "数据采集", "持久化"] ] with open(csv_path, mode="w", encoding="utf-8-sig", newline="") as f: writer = csv.writer(f) # 批量写入多行数据 writer.writerows(multi_rows) print("多行列表数据批量写入完成")
2.1.5 原理解析

writerows()接收二维列表参数,遍历外层每一个一维列表,逐行完成写入。该方法属于批量操作接口,IO 交互次数更少,在数据量较大时性能优于循环单行写入。

2.2 DictWriter 字典写入(带表头,爬虫主流用法)

2.2.1 场景分析

爬虫解析后的结构化数据基本为字典格式,每条数据的键对应字段名称,值对应字段内容。csv.DictWriter专门适配字典数据,支持自定义表头,可实现字段与数据精准映射,是正式爬虫项目的标准写法。该组件会根据表头顺序,自动提取字典中对应键的值写入单元格,无需人工排序字段。

2.2.2 单条字典数据写入

python

运行

import csv csv_path = "./news_data.csv" # 定义表头列表,决定CSV列名与列顺序 field_names = ["标题", "发布时间", "作者", "内容摘要"] # 单条字典数据,键必须与表头名称一一对应 news_dict = { "标题": "CSV文件数据持久化教程", "发布时间": "2026-06-11", "作者": "爬虫工程师", "内容摘要": "讲解Python爬虫CSV全流程存储技巧" } with open(csv_path, mode="w", encoding="utf-8-sig", newline="") as f: # 初始化字典写入器,绑定文件与表头 dict_writer = csv.DictWriter(f, fieldnames=field_names) # 写入表头(仅执行一次) dict_writer.writeheader() # 写入单条字典数据 dict_writer.writerow(news_dict) print("带表头的字典数据写入完成")
2.2.3 代码原理解析
  1. fieldnames 参数原理fieldnames用于定义 CSV 文件的表头,同时规定数据列的排列顺序。字典写入器会以此列表为依据,按顺序读取字典内对应键的值,实现字段映射。若字典缺少表头中的键,对应单元格会留空,保证文件结构不被破坏。

  2. writeheader () 方法原理该方法专门用于写入表头行,仅在文件首次创建时调用一次。重复调用会导致表头多次写入,破坏数据结构,这是开发中需要重点规避的问题。

  3. 字典映射逻辑writerow()接收字典参数,内部会遍历表头列表,依次提取字典中对应键的 value,转换为标准 CSV 行数据写入文件,全程自动完成字段匹配,大幅降低结构化数据的格式处理成本。

三、进阶实战:分页爬虫结合 CSV 批量存储

3.1 场景说明

结合第一篇分页抓取案例,实现分页采集 + 批量写入 CSV完整链路。逐页抓取网页数据,解析为字典格式,分批存入同一个 CSV 文件,同时区分首次创建文件(写入表头)与后续追加数据(不重复写入表头),模拟真实线上爬虫运行逻辑。

3.2 完整代码实现

python

运行

import csv import requests from bs4 import BeautifulSoup # 全局请求配置 HEADERS = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36" } # 爬虫与存储配置 BASE_URL = "https://demo-static-page.com/list/" CSV_SAVE_PATH = "./page_crawl_data.csv" # 定义CSV表头 FIELD_NAMES = ["新闻标题", "发布时间", "内容摘要", "所属页码"] # 分页范围 START_PAGE = 1 END_PAGE = 5 def parse_page_data(page_num): """解析单页数据,返回字典列表""" url = f"{BASE_URL}{page_num}.html" response = requests.get(url, headers=HEADERS, timeout=10) response.encoding = "utf-8" soup = BeautifulSoup(response.text, "lxml") item_list = soup.find_all("div", class_="news-item") data_list = [] for item in item_list: news_title = item.find("h3", class_="news-title").get_text(strip=True) publish_time = item.find("span", class_="publish-time").get_text(strip=True) summary = item.find("p", class_="summary").get_text(strip=True) # 封装为字典 data_dict = { "新闻标题": news_title, "发布时间": publish_time, "内容摘要": summary, "所属页码": page_num } data_list.append(data_dict) return data_list if __name__ == "__main__": # 标记文件是否为新文件,用于判断是否写入表头 is_new_file = True for page in range(START_PAGE, END_PAGE + 1): print(f"正在采集并存储第 {page} 页数据") page_data = parse_page_data(page) # 追加模式打开文件 with open(CSV_SAVE_PATH, mode="a", encoding="utf-8-sig", newline="") as f: dict_writer = csv.DictWriter(f, fieldnames=FIELD_NAMES) # 新文件写入表头,后续页面不再重复写入 if is_new_file: dict_writer.writeheader() is_new_file = False # 批量写入当前页所有数据 dict_writer.writerows(page_data) print("所有分页数据已全部存入CSV文件")

3.3 代码原理解析

  1. 文件模式选择逻辑代码中统一使用mode="a"追加模式打开文件,适配分页分批写入场景。爬虫逐页循环执行,每一页采集完成后向文件末尾追加数据,不会清空历史内容,支持断点续爬。

  2. 表头防重复机制定义布尔变量is_new_file作为标记,仅在第一次打开文件时执行writeheader()写入表头。标记置为 False 后,后续所有分页不再写入表头,从根源上解决表头重复、文件结构错乱问题,这是分页爬虫 CSV 存储的核心设计思路。

  3. writerows () 批量写入优化单页解析得到的是字典列表,直接使用writerows()批量写入,相较于循环writerow()减少文件 IO 次数,提升运行效率。IO 操作是程序性能瓶颈,批量写入是爬虫优化的基础手段。

  4. 数据结构联动原理解析函数输出的字典键名与全局表头FIELD_NAMES严格保持一致,保证字段精准匹配。若键名与表头不对应,会出现数据错位、空单元格等问题,这是结构化数据存储的基础规范。

四、CSV 数据读取实战

4.1 reader 基础读取(读取为列表)

适用于无表头或不需要区分字段的场景,读取后每一行数据转换为一维列表。

python

运行

import csv csv_path = "./multi_simple_data.csv" with open(csv_path, mode="r", encoding="utf-8-sig") as f: reader = csv.reader(f) # 遍历每一行数据 for row in reader: print(f"行数据:{row}")

原理解析csv.reader逐行读取文件内容,自动按逗号分割字段,返回列表格式数据。读取过程中会自动忽略 CSV 格式控制字符,仅保留有效业务数据。

4.2 DictReader 字典读取(带表头,主流用法)

针对带标准表头的 CSV 文件,DictReader会自动将首行作为字典的键,每行数据作为对应的值,读取结果为字典格式,字段语义清晰,便于二次数据处理。

python

运行

import csv csv_path = "./page_crawl_data.csv" with open(csv_path, mode="r", encoding="utf-8-sig") as f: # 初始化字典读取器,自动识别表头 dict_reader = csv.DictReader(f) # 遍历所有数据行 for index, row in enumerate(dict_reader, 1): print(f"第{index}条数据") print(f"标题:{row['新闻标题']},发布时间:{row['发布时间']}")

原理解析DictReader无需手动指定表头,会自动读取文件第一行作为字段名。遍历得到的每一条数据都是字典,可通过键名精准提取指定字段,适合数据筛选、清洗、二次加工等后续操作。

五、复杂场景处理与异常防护

5.1 字段包含逗号 / 换行符的兼容处理

部分采集内容(简介、正文)中会自带英文逗号、换行符,手动拼接文本会破坏 CSV 分隔规则。csv库内部已做转义处理,使用官方写入方法可自动识别特殊字符并添加引号包裹,无需开发者额外处理。

测试案例:

python

运行

import csv csv_path = "./special_char_data.csv" field_names = ["内容", "备注"] # 数据包含逗号与换行符 test_data = { "内容": "爬虫,CSV存储\n基础教程", "备注": "包含特殊符号测试" } with open(csv_path, mode="w", encoding="utf-8-sig", newline="") as f: writer = csv.DictWriter(f, fieldnames=field_names) writer.writeheader() writer.writerow(test_data) print("特殊字符数据写入完成")

运行后打开 CSV 文件可看到,特殊字符被自动包裹,表格结构保持完整,验证了库内置转义能力的可靠性。

5.2 自动创建文件与文件夹

结合os库实现路径自动化处理,若目标文件夹不存在则自动创建,避免路径报错,提升爬虫自动化程度。

python

运行

import csv import os # 定义多级路径 folder_path = "./crawl_csv/20260611" file_name = "daily_data.csv" full_path = os.path.join(folder_path, file_name) field_names = ["标题", "时间"] test_data = [{"标题": "测试数据", "时间": "2026-06-11"}] # 检测并创建文件夹 if not os.path.exists(folder_path): os.makedirs(folder_path) with open(full_path, mode="w", encoding="utf-8-sig", newline="") as f: writer = csv.DictWriter(f, fieldnames=field_names) writer.writeheader() writer.writerows(test_data) print("多级目录CSV文件创建写入完成")

5.3 异常捕获与容错处理

网络异常、文件权限不足、磁盘空间已满等问题都会导致 CSV 读写失败,在核心逻辑外层增加try...except异常捕获,保证程序稳定运行。

python

运行

import csv import requests from bs4 import BeautifulSoup HEADERS = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36"} CSV_PATH = "./error_protect.csv" FIELD_NAMES = ["标题", "时间"] try: # 采集数据 res = requests.get("https://demo-static-page.com/list/1.html", headers=HEADERS, timeout=10) res.encoding = "utf-8" soup = BeautifulSoup(res.text, "lxml") title = soup.find("h1").get_text(strip=True) data = [{"标题": title, "时间": "2026-06-11"}] # 写入CSV with open(CSV_PATH, mode="a", encoding="utf-8-sig", newline="") as f: writer = csv.DictWriter(f, fieldnames=FIELD_NAMES) writer.writerows(data) print("数据写入成功") except FileNotFoundError: print("文件路径错误,目录不存在") except PermissionError: print("文件权限不足,无法写入") except Exception as e: print(f"程序运行异常:{str(e)}")

六、CSV 存储性能优化方案

6.1 减少文件打开关闭次数

分页爬虫循环中,若每一页都重复打开、关闭文件,会产生大量 IO 开销。优化方案为:将文件打开操作移至循环外部,全程保持文件打开状态,循环内持续写入,所有分页采集完成后自动关闭文件。

优化示例:

python

运行

import csv csv_path = "./optimize_csv.csv" field_names = ["字段1", "字段2"] data_list = [{"字段1": f"数据{i}", "字段2": f"内容{i}"} for i in range(100)] # 单次打开文件,循环内持续写入 with open(csv_path, mode="w", encoding="utf-8-sig", newline="") as f: writer = csv.DictWriter(f, fieldnames=field_names) writer.writeheader() for data in data_list: writer.writerow(data) print("优化后写入完成")

6.2 批量缓存写入

数据量极大时,可设置缓存列表,采集多条数据后统一批量写入,进一步降低 IO 交互频率,提升整体运行速度。该方案适用于高并发、海量数据采集场景。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询