Peewee在爬虫中容易出现并发写入、字段类型误用和异常处理不当等问题:SqliteDatabase默认check_same_thread=True导致多线程错误报告;CharField长度限制容易切断HTML等长内容,应优先使用TextField;重复插入需要get__or_create()或on__conflict_ignore()避免Integrityerrorororrororro;爬虫场景下应关闭自动时间戳和外键,以提高性能和稳定性。
Peewee 模板代码可以显著减少爬虫数据的存储,但在并发、字段类型和异常处理中直接应用默认配置很容易翻车。
为什么在爬虫场景中SqliteDatabase 默认不支持多线程写入
Peewee 的 SqliteDatabase 默认启用 check_same_thread=True,而且大多数爬虫都会用 concurrent.futures 或 asyncio 并发采集-此时,多个线程共用一个连接 sqlite3.ProgrammingError: SQLite objects created in a thread can only be used in that same thread。
- 必须显式关闭检查:
db = SqliteDatabase('data.db', check_same_thread=False) - 更安全的方法是分配独立连接到每个线程/协程
db.bind()+db.connect()控制生命周期 - 避免在模型定义前调用
db.connect(),否则,主线程连接可能会提前建立,后续子线程仍会报错
TextField 和 CharField 存储网页内容时如何选择?
爬虫常存 HTML 片段、JSON 字符串或长文摘要,CharField 有长度限制(SQLite 默认 255),而 TextField 是无界字符串的实际载体。
- 标题、URL 等待用于固定短字段
CharField(max_length=512),便于加索引 - 正文、HTML 所有的源代码和评论内容都将被使用
TextField(),别试图设max_length——SQLite 这个参数没有被强制,但是 Peewee 会做 Python 层层验证,徒增费用 - 如果字段可能是空的,则需要区分
NULL和空字符串,显式声明null=True,否则默认NOT NULL,插入空值会报IntegrityError
IntegrityError
爬虫去重通常靠 URL 或者唯一的标识符,但是 Peewee 没有内置的“存在就更新”逻辑 .create() 遇到主键/唯一的约束冲突就会爆炸。
Python 3.14.2
Python 3.14.2是Python编程语言于2025年12月5日发布的稳定版本,属于3.14系列的第二次维护更新。该版本包含18个修复项目,重点解决多过程、数据和正则表达模块的回归问题,修复CVE-2025-12084等安全漏洞。这个版本标志着Python发展的一个重要里程碑,即自由线程模式(删除GIL)正式得到官方支持。
下载立即学习“Python免费学习笔记(深入);
- 用
get_or_create():唯一适用于单字段(如url),返回 (instance,created) 注意元组只对主键或unique=True字段生效 - 更灵活的方法是捕获异常:
try: model.create(...) except IntegrityError: pass,但必须确保已设置url = CharField(unique=True) - 不要在批量插入时使用循环
create(),改用model.insert_many(...).on_conflict_ignore().execute()(SQLite 3.24+ 支持),高性能和原子,
auto_timestamps 和 foreign_key
Peewee 的 BaseModel 如果打开自动时间戳或外键约束,在爬虫等高吞吐、低关系语义的情况下,会减速,增加错误路径。
-
created_at = DateTimeField(default=datetime.now)比AutoNow避免时区或序列化问题更可控 - 除非明确需要级联删除(如文章和评论强绑定),否则在定义外键时会添加
constraints=[SQL('FOREIGN KEY (xxx_id) REFERENCES xxx(id) ON DELETE NO ACTION')],并手动控制相关逻辑 - SQLite 即使写了外键,默认也不会强制外键
ForeignKeyField它不生效,必须额外调用db.execute_sql('PRAGMA foreign_keys = ON')
真正的麻烦不是写几行 create_table,但是,在错误的字段类型选择后,数据被切断,数据库被并发地编写和崩溃,或者唯一的验证被遗漏,导致脏数据堆积——这些坑通常需要几天的时间才能暴露。