前言
爬虫采集场景中,大量数据属于非结构化、半结构化形态:长短不一的文章正文、嵌套层级复杂的 JSON 数据、混合图文的富文本、动态变化的字段、不规则标签属性等,此类数据无法用固定字段的 MySQL 关系表高效承载。
MongoDB 作为文档型 NoSQL 数据库,以 BSON 文档为存储单元, schema 弱约束、字段动态扩展、天然适配嵌套结构、写入吞吐量大,完美适配爬虫不规则数据存储需求,成为短视频、资讯、评论、社交类爬虫的首选持久化方案。
原生单条循环插入、无索引、写入无限流、大文档无分片等写法,会导致 MongoDB 写入卡顿、磁盘占用激增、查询缓慢、内存溢出等问题。本文围绕爬虫专属场景,讲解 MongoDB 基础连接、批量写入、索引优化、内存控制、去重策略、大文档处理、集群适配等工程级优化方案,全部代码可直接投产,适配中小型单机爬虫至分布式大规模爬虫项目。
一、MongoDB 核心优势与爬虫适配场景
1.1 核心特性
- 文档存储:每条数据为独立 JSON 格式文档,字段自由增减,无需提前建表;
- 嵌套支持:天然适配多层嵌套数据,无需复杂关联表设计;
- 高吞吐写入:内存映射机制,并发写入性能远优于传统关系库;
- 灵活查询:支持模糊查询、嵌套查询、条件筛选,适配爬虫数据检索;
- 部署简单:单机快速部署,轻量化运维,适合爬虫快速迭代。
1.2 爬虫典型适用场景
- 评论、弹幕、用户动态等层级嵌套数据;
- 网页富文本、混合标签、不规则详情内容;
- 接口 JSON 原始数据全量留存;
- 多站点异构数据统一存储,字段不统一场景;
- 高频增量采集、高并发写入业务。
二、环境部署与依赖安装
2.1 依赖安装
bash
运行
pip install pymongo2.2 基础连接配置
区分本地单机、远程服务器、账号密码认证三种常用模式:
python
运行
from pymongo import MongoClient import time # 1. 本地无密码连接 client = MongoClient("mongodb://127.0.0.1:27017") # 2. 远程带账号密码 # client = MongoClient("mongodb://user:pwd@ip:27017/") # 选择数据库 & 集合 db = client["crawler_db"] coll = db["article_data"]数据库对应 MySQL 库,集合对应数据表,文档对应单条数据。
三、基础写入方式及性能缺陷
3.1 单条插入
python
运行
def insert_one_data(item: dict): coll.insert_one(item)缺陷:频繁网络交互、请求次数多、万级数据写入缓慢,并发场景极易阻塞爬虫主线程。
3.2 普通批量插入
python
运行
def insert_many_data(data_list: list): coll.insert_many(data_list)优点:单次请求写入多条,效率大幅提升;隐患:数据量过大时单请求载荷过高,易触发超时、断连、内存飙升。
四、爬虫高性能分批写入优化
4.1 分块批量写入(核心方案)
控制单次写入文档数量,平衡网络载荷与写入效率,爬虫通用最优方案:
python
运行
def batch_insert(data_list, chunk_size=500): """分批写入MongoDB,默认每批500条""" total = len(data_list) count = 0 for i in range(0, total, chunk_size): chunk = data_list[i:i+chunk_size] coll.insert_many(chunk) count += len(chunk) print(f"MongoDB批量入库:{count}/{total}")适用绝大多数爬虫项目,兼顾稳定性与写入速度。
4.2 有序 / 无序写入优化
insert_many 支持 ordered 参数:
- ordered=True:有序写入,单条报错整体终止,适合强数据一致性;
- ordered=False:无序写入,错误跳过、继续写入,爬虫首选。
改造增强版:
python
运行
def batch_insert_safe(data_list, chunk_size=500): for i in range(0, len(data_list), chunk_size): chunk = data_list[i:i+chunk_size] coll.insert_many(chunk, ordered=False)自动跳过脏数据、异常文档,保证批量写入不中断。
五、爬虫数据去重方案
爬虫重复采集是高频问题,MongoDB 提供两种高效去重手段。
5.1 唯一索引强制去重
以文章 url、id 等唯一字段创建索引,重复自动拦截:
python
运行
# 唯一索引,重复数据写入直接报错跳过 coll.create_index("data_url", unique=True)5.2 存在则更新、不存在则插入
使用 update_one + upsert,实现智能去重合并:
python
运行
def upsert_item(item): coll.update_one( {"data_url": item["data_url"]}, {"$set": item}, upsert=True )逻辑:链接存在则更新字段,不存在新增,适合增量更新类爬虫。
六、索引优化,解决查询卡顿
爬虫后期数据检索、筛选、分页查询频繁,无索引会造成全表扫描。
6.1 常用索引创建
python
运行
# 单字段索引 coll.create_index("crawl_time") # 复合索引 coll.create_index([("data_source",1),("publish_time",-1)]) # 过期索引(自动清理过期爬虫数据) coll.create_index("expire_time", expireAfterSeconds=2592000)优化要点:
- 高频查询字段建立索引;
- 时间字段做倒序索引,适配最新数据查询;
- 临时采集数据配置自动过期,减少磁盘占用。
七、大文档与嵌套数据优化
爬虫常存在超大文本、多层嵌套 JSON,易导致写入膨胀、查询缓慢。
- 超大文本拆分:超长 content 单独存储或压缩后入库;
- 嵌套层级精简:不必要的深层结构扁平化;
- 字段过滤:入库前剔除无效空字段、冗余参数,减小单文档体积。
八、写入限流与并发控制
高并发爬虫瞬间大量写入,会压垮 MongoDB 服务,增加限流休眠:
python
运行
def batch_insert_limit(data_list, chunk_size=300, sleep=0.1): for i in range(0, len(data_list), chunk_size): chunk = data_list[i:i+chunk_size] coll.insert_many(chunk, ordered=False) time.sleep(sleep)控制写入频率,降低数据库 CPU、IO 负载。
九、内存与磁盘优化策略
- 关闭不必要日志,减少磁盘 IO;
- 定期执行碎片整理,压缩存储空间;
- 冷热数据分离,历史爬虫数据归档至次级集合;
- 限制单集合数据量,超大体量分表分库存储。
十、异常捕获与容错封装
生产级爬虫必须增加异常捕获,防止程序崩溃:
python
运行
from pymongo.errors import PyMongoError def safe_batch_insert(data_list): try: coll.insert_many(data_list, ordered=False) return True except PyMongoError as e: print(f"MongoDB写入异常:{str(e)}") return False十一、MongoDB 与 MySQL 爬虫选型对比
表格
| 特性 | MongoDB | MySQL |
|---|---|---|
| 数据结构 | 非结构化、嵌套友好 | 结构化固定字段 |
| 写入速度 | 高吞吐、并发强 | 中等 |
| 查询复杂度 | 灵活、适配不规则数据 | 复杂关联更稳定 |
| 维护成本 | 低 | 偏高 |
| 适用爬虫 | 资讯、评论、动态、接口原始数据 | 商品、榜单、规整结构化数据 |
十二、总结
MongoDB 凭借灵活的文档结构、高吞吐写入能力,是非结构化爬虫数据的最优存储方案。通过分批无序写入、唯一索引去重、合理索引、写入限流、异常容错多重优化,可彻底解决大批量爬虫写入卡顿、数据重复、查询缓慢、服务过载等问题。
整套方案轻量化、易部署、改造成本低,可快速集成至现有爬虫项目,适配单机爬虫、分布式爬虫多类业务场景。