mongodb写入需验证连接、规范批量操作、处理bson类型限制并避免_id冲突;初始化后执行ping检测,用insert_many(..., ordered=false)批量写入,构造确定性_id并建唯一索引,统一datetime等数据类型。

写入前必须确认MongoDB连接是否真正可用
很多新手调用 pymongo.MongoClient() 后直接写入,却没意识到连接是惰性建立的——直到第一次执行操作(比如 insert_one())才真正尝试连数据库。如果网络不通、认证失败或端口被拒,错误会延迟抛出,且堆栈信息容易误导人以为是写入逻辑的问题。
实操建议:
- 初始化客户端后立即执行
client.admin.command('ping'),捕获pymongo.errors.ConnectionFailure或pymongo.errors.OperationFailure - 避免把
MongoClient实例放在循环内创建——它本身是线程安全、可复用的,重复新建会耗尽 socket 资源 - 生产环境务必设置超时参数:
MongoClient(host, serverSelectionTimeoutMS=5000, connectTimeoutMS=5000)
批量插入比单条 insert\_one() 快 10 倍以上,但要注意文档大小和顺序
insert_many() 是爬虫写入 MongoDB 的首选方式,但默认行为可能踩坑:它会按传入列表顺序逐条尝试插入,一旦某条文档因重复键(DuplicateKeyError)或字段类型不符失败,后续文档将全部跳过(除非显式设置 ordered=False)。
实操建议:
- 始终使用
insert_many(docs, ordered=False),让成功文档继续写入,失败项单独捕获处理 - 单次传入文档数控制在 100–500 条之间;超过 16MB(MongoDB 单次请求上限)会报
DocumentTooLarge - 提前过滤掉空字典、含不可序列化对象(如
datetime.date而非datetime.datetime)的文档,否则insert_many()会在序列化阶段直接崩溃
避免 _id 冲突的关键是别让 pymongo 自动生成重复值
爬虫数据常含 URL、标题等天然去重字段。如果直接让 MongoDB 自动生成 _id(ObjectId),就无法利用唯一索引去重,后续查重或更新成本极高。但手动设 _id 又容易因类型不一致(比如字符串 vs ObjectId)导致意外覆盖或冲突。
实操建议:
- 用业务字段构造确定性
_id,例如{'_id': hashlib.md5(url.encode()).hexdigest()},确保每次运行结果一致 - 提前在集合上建唯一索引:
collection.create_index('_id', unique=True),配合insert_many(..., ordered=False)自动跳过重复 - 切勿用
update_one(..., upsert=True)替代去重插入——它在高并发写入时可能因竞态条件产生多份副本
中文乱码、时间字段丢失精度、嵌套结构崩塌都是 BSON 序列化惹的祸
pymongo 底层用 BSON 协议通信,它对 Python 类型有严格映射规则。爬虫常见数据如 datetime.date、float('inf')、set、自定义类实例,都无法直接存入,会报 TypeError: <...> is not a valid BSON type</...>。
实操建议:
- 统一用
datetime.datetime替代datetime.date;若只有日期,补上time.min:datetime.combine(d, time.min) - 遇到
NaN、inf,转成None或字符串(BSON 不支持 IEEE 754 特殊浮点值) - 嵌套字典里若有
list混了不同结构(如[{'a':1}, 'str']),BSON 允许但查询会异常;建议预处理为同构结构 - 中文无需额外编码——只要 Python 字符串是
str类型(不是bytes),pymongo 会自动 UTF-8 编码
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











