Python3 爬虫数据存储:MongoDB 操作指南

1. NoSQL 数据库概述

NoSQL(Not Only SQL)泛指非关系型数据库,具有以下特点:

  • 基于键值对存储
  • 无需 SQL 层解析
  • 数据结构灵活,无严格模式
  • 高性能,适合大规模数据存储

NoSQL 数据库分类

类型特点代表产品
键值存储简单高效,适合缓存Redis, Voldemort, Oracle BDB
列存储适合分析型应用Cassandra, HBase, Riak
文档型类似JSON格式,灵活MongoDB, CouchDB
图形数据库擅长处理关系Neo4J, InfoGrid

2. MongoDB 简介

MongoDB 是一个基于分布式文件存储的开源文档数据库:

  • 使用 C++ 编写
  • 数据格式类似 JSON(BSON)
  • 支持嵌套文档和数组
  • 灵活的模式设计

3. 环境准备

安装 MongoDB

推荐使用官方安装指南或 Docker 方式:

docker run -d -p 27017:27017 --name mongodb mongo:latest

安装 PyMongo

pip install pymongo

4. 基本操作

连接 MongoDB

from pymongo import MongoClient

# 方式1:分别指定主机和端口
client = MongoClient('localhost', 27017)

# 方式2:使用连接字符串
client = MongoClient('mongodb://localhost:27017/')

选择数据库和集合

# 选择数据库
db = client['test']  # 或 db = client.test

# 选择集合
collection = db['students']  # 或 collection = db.students

5. CRUD 操作

插入数据

# 插入单条数据
student = {
    'id': '20170101',
    'name': 'Jordan',
    'age': 20,
    'gender': 'male'
}
result = collection.insert_one(student)
print(result.inserted_id)

# 批量插入
students = [
    {'id': '20170102', 'name': 'Mike', 'age': 21, 'gender': 'male'},
    {'id': '20170103', 'name': 'Mary', 'age': 22, 'gender': 'female'}
]
result = collection.insert_many(students)
print(result.inserted_ids)

查询数据

# 查询单条
result = collection.find_one({'name': 'Mike'})
print(result)

# 查询多条
results = collection.find({'age': {'$gt': 20}})
for result in results:
    print(result)

# 使用正则查询
results = collection.find({'name': {'$regex': '^M.*'}})

更新数据

# 更新单条
result = collection.update_one(
    {'name': 'Mike'},
    {'$set': {'age': 25}}
)
print(result.matched_count, result.modified_count)

# 更新多条
result = collection.update_many(
    {'age': {'$gt': 20}},
    {'$inc': {'age': 1}}
)

删除数据

# 删除单条
result = collection.delete_one({'name': 'Mike'})
print(result.deleted_count)

# 删除多条
result = collection.delete_many({'age': {'$lt': 25}})
print(result.deleted_count)

6. 高级查询

比较运算符

符号含义示例
$lt小于{'age': {'$lt': 20}}
$gt大于{'age': {'$gt': 20}}
$lte小于等于{'age': {'$lte': 20}}
$gte大于等于{'age': {'$gte': 20}}
$ne不等于{'age': {'$ne': 20}}
$in在范围内{'age': {'$in': [20, 22]}}
$nin不在范围内{'age': {'$nin': [20, 22]}}

其他查询操作

# 计数
count = collection.count_documents({'age': {'$gt': 20}})
print(count)

# 排序
results = collection.find().sort('age', pymongo.DESCENDING)

# 分页
results = collection.find().skip(2).limit(2)

7. 索引管理

# 创建索引
collection.create_index([('name', pymongo.ASCENDING)], unique=True)

# 获取索引
indexes = collection.list_indexes()
for index in indexes:
    print(index)

# 删除索引
collection.drop_index('name_1')

8. 聚合操作

pipeline = [
    {'$match': {'gender': 'male'}},
    {'$group': {'_id': '$age', 'count': {'$sum': 1}}}
]
results = collection.aggregate(pipeline)
for result in results:
    print(result)

9. 最佳实践

  1. 连接池管理:重用 MongoClient 实例
  2. 批量操作:优先使用 bulk_write
  3. 索引优化:为常用查询字段创建索引
  4. 数据安全:启用身份验证
  5. 错误处理:捕获 PyMongo 异常
from pymongo.errors import PyMongoError

try:
    # 数据库操作
    pass
except PyMongoError as e:
    print(f"Database error: {e}")

10. 最新特性

PyMongo 4.x 新增功能:

  • 支持 MongoDB 5.0+ 新特性
  • 更好的类型提示
  • 更完善的异步支持
  • 增强的事务功能

11. 资源推荐

12. 完整示例

import pymongo
from pymongo import MongoClient

# 连接数据库
client = MongoClient('mongodb://localhost:27017/')

# 获取数据库和集合
db = client['school']
students = db['students']

# 插入测试数据
students.insert_many([
    {'name': 'Alice', 'age': 20, 'courses': ['Math', 'Physics']},
    {'name': 'Bob', 'age': 22, 'courses': ['Chemistry', 'Biology']},
    {'name': 'Charlie', 'age': 21, 'courses': ['Math', 'Computer Science']}
])

# 复杂查询
result = students.find({
    'age': {'$gte': 20, '$lte': 22},
    'courses': 'Math'
}).sort('age', pymongo.ASCENDING)

for doc in result:
    print(doc)

# 聚合查询
pipeline = [
    {'$unwind': '$courses'},
    {'$group': {'_id': '$courses', 'count': {'$sum': 1}}},
    {'$sort': {'count': -1}}
]
agg_result = students.aggregate(pipeline)
print("Popular courses:")
for item in agg_result:
    print(f"{item['_id']}: {item['count']}")

# 清理数据
students.delete_many({})

通过本教程,您应该已经掌握了使用 PyMongo 操作 MongoDB 的基本方法。在实际爬虫项目中,MongoDB 的灵活数据结构特别适合存储非结构化的网页数据。