【爬虫入门第7讲】Python爬虫数据持久化全攻略
Python爬虫数据持久化全攻略:从文本到数据库的完整实践
在数据驱动的时代,爬虫是获取网络信息的重要工具。然而,爬取到的数据若只停留在内存中,便如同沙上建塔——程序一停,一切归零。数据持久化是将爬取结果稳定存储的关键环节,它决定了数据能否被后续分析、可视化或长期使用。本文将从最简单的文本文件,到结构化的表格,再到功能强大的数据库,系统梳理Python爬虫中常用的数据持久化方案,并结合实际场景给出选型建议。
一、文本持久化:轻量级存储的基石
文本文件是最直接、最通用的持久化方式,适合存储非结构化或半结构化数据。Python内置的文件操作和json模块足以应对大多数简单场景。
1.1 纯文本(.txt)存储
适用场景:爬取新闻标题、评论内容、日志等纯文本信息,无需复杂结构。
# 写入
# 写入
with open('data.txt', 'a', encoding='utf-8') as f:
f.write('爬取内容\n')
# 读取
with open('data.txt', 'r', encoding='utf-8') as f:
content = f.read()
注意事项:
- 使用
with语句自动管理文件句柄,避免资源泄漏。 - 指定
encoding='utf-8'处理中文,否则可能乱码。 - 追加模式
'a'适合持续写入,覆盖模式'w'适合重新生成。
局限性:无结构,检索困难,不适合大规模数据。
1.2 JSON文件存储
JSON(JavaScript Object Notation)是爬虫中最常用的结构化文本格式,天然支持Python字典和列表的序列化。
import json
data = [
{"title": "Python入门", "url": "https://example.com/1"},
{"title": "爬虫进阶", "url": "https://example.com/2"}
]
# 写入
with open('data.json', 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=4)
# 读取
with open('data.json', 'r', encoding='utf-8') as f:
loaded_data = json.load(f)
关键参数:
ensure_ascii=False:保留中文,而非转义为\u序列。indent=4:美化输出,便于人工阅读。
优势:跨语言兼容、可读性好、支持嵌套结构。适合中小规模数据(如几万条记录)的快速存储与交换。
注意:JSON文件是整体读写,当数据量极大(如百万级)时,内存占用和读写效率会成为瓶颈。此时可考虑逐行写入JSON Lines(.jsonl)格式,每行一个独立JSON对象。
二、表格持久化:结构化数据的首选
当数据具有明确的列字段(如商品名称、价格、销量),表格文件是最直观的存储方式。CSV(逗号分隔值)是通用表格格式,Python提供了内置csv模块和第三方库pandas两种实现路径。
2.1 使用内置csv模块
csv模块轻量、零依赖,适合简单场景。
import csv
headers = ['name', 'price', 'sales']
rows = [
['Python书', 59.9, 1200],
['爬虫书', 49.9, 800]
]
# 写入
with open('products.csv', 'w', newline='', encoding='utf-8-sig') as f:
writer = csv.writer(f)
writer.writerow(headers)
writer.writerows(rows)
# 读取
with open('products.csv', 'r', encoding='utf-8-sig') as f:
reader = csv.reader(f)
for row in reader:
print(row)
细节:
newline='':避免Windows下出现空行。encoding='utf-8-sig':添加BOM头,使Excel能正确识别UTF-8中文。- 使用
DictWriter/DictReader可以按列名操作,更直观。
局限:处理复杂数据类型(如列表、字典)需手动序列化;大数据量时性能一般。
2.2 使用pandas库
pandas是数据分析领域的瑞士军刀,其DataFrame对象与CSV的交互极为便捷,且内置了类型推断、缺失值处理等功能。
import pandas as pd
df = pd.DataFrame({
'name': ['Python书', '爬虫书'],
'price': [59.9, 49.9],
'sales': [1200, 800]
})
# 写入
df.to_csv('products_pd.csv', index=False, encoding='utf-8-sig')
# 读取
df_read = pd.read_csv('products_pd.csv')
print(df_read)
优势:
- 一行代码完成读写,自动处理引号、转义等细节。
- 支持多种编码、分隔符(
sep参数可改为\t生成TSV)。 - 可配合
chunksize参数分块读取大文件,避免内存溢出。
适用场景:数据清洗、分析、可视化前的中间存储;需要频繁进行行列操作的场景。
对比总结:
| 特性 | csv模块 | pandas |
|---|---|---|
| 依赖 | 内置 | 需安装(约50MB) |
| 性能 | 中等 | 底层C优化,大数据更快 |
| 功能 | 基础读写 | 类型推断、缺失值处理、分块读取 |
| 学习成本 | 低 | 中(需了解DataFrame) |
建议:简单爬虫用csv模块,涉及数据分析或复杂处理用pandas。
三、数据库持久化:从轻量到企业级
当数据量达到十万级以上,或需要频繁查询、更新、关联操作时,数据库是必然选择。Python爬虫常用的数据库包括SQLite、MySQL和Redis,它们分别适用于不同量级和场景。
3.1 SQLite:嵌入式轻量数据库
SQLite是一个文件型数据库,无需安装服务,Python内置sqlite3模块支持。适合单机爬虫、移动端或嵌入式设备。
import sqlite3
# 连接(自动创建文件)
conn = sqlite3.connect('crawler.db')
cursor = conn.cursor()
# 建表
cursor.execute('''
CREATE TABLE IF NOT EXISTS products (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
price REAL,
sales INTEGER,
crawl_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
''')
# 插入
cursor.execute('INSERT INTO products (name, price, sales) VALUES (?, ?, ?)',
('Python书', 59.9, 1200))
# 批量插入
data = [('爬虫书', 49.9, 800), ('算法书', 69.9, 600)]
cursor.executemany('INSERT INTO products (name, price, sales) VALUES (?, ?, ?)', data)
conn.commit()
conn.close()
关键点:
- 使用参数化查询(
?占位符)防止SQL注入。 - 每次操作后需
commit()提交事务。 - 支持事务回滚,适合爬虫中断时的数据一致性。
优势:零配置、单文件、跨平台、支持标准SQL。适合数据量在百万级以内、并发写入不高的场景。
注意:SQLite不支持高并发写入(写操作会锁表),不适合多线程爬虫同时写入。
3.2 MySQL:生产级关系数据库
当爬虫需要服务多用户、高并发访问,或数据量达到千万级,MySQL是更可靠的选择。Python通过pymysql或mysql-connector-python连接。
import pymysql
conn = pymysql.connect(
host='localhost',
user='root',
password='your_password',
database='crawler_db',
charset='utf8mb4'
)
cursor = conn.cursor()
# 建表(与SQLite类似,但支持更多数据类型)
cursor.execute('''
CREATE TABLE IF NOT EXISTS products (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
price DECIMAL(10,2),
sales INT,
crawl_time DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
''')
# 插入(使用参数化)
sql = 'INSERT INTO products (name, price, sales) VALUES (%s, %s, %s)'
cursor.execute(sql, ('Python书', 59.9, 1200))
conn.commit()
cursor.close()
conn.close()
与SQLite的区别:
- 需要安装MySQL服务,配置用户权限。
- 支持高并发(InnoDB引擎行级锁)。
- 支持存储过程、视图、触发器。
- 数据类型更丰富(如
DECIMAL适合金额)。
最佳实践:
- 使用连接池(如
DBUtils)避免频繁创建连接。 - 批量插入时使用
executemany或LOAD DATA LOCAL INFILE提升性能。 - 爬虫中断时利用事务回滚,保证数据完整性。
3.3 Redis:缓存与高速存储
Redis是基于内存的键值数据库,读写速度极快(微秒级),适合爬虫中的去重、临时存储、任务队列等场景。Python通过redis库操作。
import redis
r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
# 字符串:存储单个值
r.set('crawl_status', 'running')
print(r.get('crawl_status')) # 'running'
# 列表:模拟队列(先进先出)
r.lpush('url_queue', 'https://example.com/page1')
r.lpush('url_queue', 'https://example.com/page2')
while r.llen('url_queue') > 0:
url = r.rpop('url_queue')
print(url)
# 集合:去重(爬虫URL去重利器)
r.sadd('visited_urls', 'https://example.com/page1')
if r.sismember('visited_urls', 'https://example.com/page1'):
print('已访问,跳过')
# 哈希:存储结构化数据
r.hset('product:1', mapping={'name': 'Python书', 'price': 59.9})
print(r.hgetall('product:1'))
典型应用:
- URL去重:使用
SADD/SISMEMBER,比数据库查询快几个数量级。 - 请求队列:使用列表实现生产者-消费者模式,支持多线程/多进程爬虫。
- 临时缓存:存储频繁访问的页面或中间结果,减少重复请求。
- 计数器:使用
INCR统计爬取数量。
注意:Redis数据默认存储在内存中,需配置持久化(RDB/AOF)防止数据丢失。不适合存储大量原始数据(成本高),通常作为数据库的缓存层。
四、综合实践:爬虫数据持久化选型指南
在实际爬虫项目中,往往需要组合多种持久化方式。以下是一个典型的多层存储架构:
爬虫引擎 → 临时存储(Redis) → 清洗/去重 → 持久化存储(MySQL/文件)
选型决策树:
- 数据量 < 1万条,且无需复杂查询 → 文本文件(JSON/CSV)
- 数据量 1万~100万条,单机运行 → SQLite
- 数据量 > 100万条,需要多用户访问 → MySQL/PostgreSQL
- 需要高速缓存、去重、队列 → Redis(配合上述数据库)
- 数据需要频繁分析、可视化 → 先用CSV/pandas快速处理,再导入数据库
示例:爬取电商商品信息
# 伪代码:结合Redis去重 + MySQL存储
import redis
import pymysql
r = redis.Redis(decode_responses=True)
conn = pymysql.connect(...)
def crawl_product(url):
if r.sismember('visited_urls', url):
return # 已爬取
# 爬取逻辑...
product_data = {'name': ..., 'price': ...}
# 写入MySQL
with conn.cursor() as cursor:
cursor.execute('INSERT INTO products ...', product_data)
conn.commit()
# 标记已访问
r.sadd('visited_urls', url)
五、总结与最佳实践
数据持久化是爬虫工程中不可忽视的一环。从简单的文本文件到高性能的数据库,每种方案都有其适用边界:
- 文本文件:快速原型、小规模数据、跨平台交换。
- CSV/pandas:结构化表格数据,兼顾可读性与分析能力。
- SQLite:单机轻量级数据库,零配置,适合个人项目。
- MySQL:企业级关系数据库,支持高并发与复杂查询。
- Redis:内存级高速存储,专为缓存、去重、队列而生。
最后几点建议:
- 始终使用参数化查询防止SQL注入。
- 合理设置编码(UTF-8/UTF-8-sig)避免乱码。
- 对于大规模爬虫,采用分批写入、事务提交、错误重试机制。
- 定期备份数据库,尤其是生产环境。
掌握这些持久化技术,你的爬虫将不再是“一次性”工具,而是能够持续产出价值的可靠数据管道。希望本文能帮助你在爬虫开发中做出更明智的存储选择。
更多推荐


所有评论(0)