会,因为pipeline默认同步执行,直接调用阻塞式数据库操作会拖慢整个twisted事件循环;应使用连接池、缓冲批量写入和事务优化。

Scrapy Pipeline里直接写数据库会卡住爬虫吗?
会,而且很常见。默认情况下 Item Pipeline 是同步执行的,如果在 process_item 里用 sqlite3.connect() 或 psycopg2.connect() 做阻塞式插入,每条 item 都要等数据库返回才继续,吞吐量直接掉到个位数。
根本原因不是数据库慢,而是 Scrapy 的 pipeline 运行在 Twisted 的主线程(或默认的同步线程池)里,没做异步封装就硬连数据库,等于把整个爬虫拖进 IO 等待队列。
- 别在
process_item里调cursor.execute()+conn.commit() - 批量写入必须绕过单条提交,至少攒够 100 条再发一次 INSERT
- MySQL/PostgreSQL 推荐用
executemany();SQLite 可用事务包裹多条INSERT
如何用 SQLite 实现带缓冲的批量写入 Pipeline?
SQLite 虽轻量,但频繁打开/关闭连接、不加事务、逐条 INSERT 依然极慢。关键不是“能不能写”,而是“怎么避免每次 process_item 都触发磁盘 IO”。
实操建议:
- 在
open_spider里初始化一个连接和空列表:self.items_buffer = [],self.conn = sqlite3.connect("data.db") -
process_item只做self.items_buffer.append(item),不碰数据库 - 在
close_spider里统一执行:开启事务 →executemany→ 提交 → 关闭连接 - 如果怕内存爆,可在
process_item里加缓冲阈值,比如if len(self.items_buffer) >= 100:就 flush 一次
示例片段(SQLite 批量插入):
TikHub API 多平台数据爬取工具,支持抖音/TikTok/B站等。用户提及以下需求时调用:1) 爬取视频或评论;2) 获取用户信息/粉丝列表;3) 批量下载无水印视频;4) 抖音链接转文字(下载→音频→Whisper pipeline);5) 调用 TikHubAPI。
def close_spider(self, spider):
if self.items_buffer:
cursor = self.conn.cursor()
cursor.executemany(
"INSERT INTO books (title, price) VALUES (?, ?)",
[(item["title"], item["price"]) for item in self.items_buffer]
)
self.conn.commit()
self.conn.close()
PostgreSQL 或 MySQL 怎么避免连接池耗尽?
用 psycopg2 或 pymysql 直接在 pipeline 里 new connection,爬 10 万条可能建 10 万个连接,数据库直接拒绝新连接 —— 错误信息通常是 too many clients already 或 max_connections exceeded。
必须引入连接复用机制:
- 不要每次
process_item都connect(),改用psycopg2.pool.ThreadedConnectionPool - 在
from_crawler类方法里初始化连接池,绑定到 pipeline 实例 - 写入逻辑仍走缓冲 +
executemany,但从池里getconn()/putconn(),不是新建 - 注意:Twisted 和 Scrapy 默认不支持 asyncpg,别强行套
await,会报RuntimeError: no running event loop
为什么用 SQLAlchemy ORM 在 Pipeline 里容易翻车?
很多人想用 session.add(item) + session.commit() 图省事,结果发现速度比裸 SQL 还慢,甚至内存持续上涨。
问题出在 ORM 层的开销和 session 管理上:
- 每个
add()都触发对象状态跟踪,10 万条 item = 10 万个 Python 对象被 session 持有 -
commit()不等于批量提交,它只是刷出 pending changes,底层仍是 N 条 INSERT - 正确姿势是:禁用 autocommit、禁用 autoflush,攒够一批后用
session.bulk_insert_mappings()或直接走engine.execute() - 更推荐绕过 ORM,用
engine.execute(text("INSERT ..."), batch_data),减少抽象层损耗
真正难的不是“怎么写进去”,而是“怎么让 pipeline 不成为瓶颈,同时不把数据库压垮”。缓冲大小、连接复用、事务粒度,这三个点调不好,跑着跑着就会发现日志里全是超时或连接拒绝。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










