本文目录导读:
Python数据存储爬虫案例精讲:从采集到数据库的高效实战
目录导读
- 案例背景与需求分析
- Python爬虫核心框架选型
- 目标数据结构化与清洗
- 数据存储方案对比(CSV/MySQL/MongoDB)
- 完整爬虫存储代码拆解(附可运行示例)
- 常见错误与性能优化技巧
- 问答环节(FAQ)
案例背景与需求分析
在当今信息爆炸的互联网环境中,许多程序员面临一个实际问题:如何从网页中抓取公开数据,并持久化存储以供分析? 本文以“爬取某电影网站TOP250榜单”为例,演示从请求发送到数据入库的全流程。
核心挑战:动态页面加载、反爬机制应对、存储格式选择。
Python爬虫核心框架选型
根据搜索引擎最新实践,推荐以下组合:
- 请求库:
requests(轻量可靠)或aiohttp(异步高频) - 解析库:
BeautifulSoup+lxml(适合静态HTML),Selenium(处理JS渲染) - 存储库:
pymysql(关系型)、pymongo(文档型)、内置csv模块
本案例采用 requests + BeautifulSoup + pymysql 组合,兼顾效率与代码可读性。
目标数据结构化与清洗
原始网页数据通常包含:
- 电影名称(需去除多余空格)
- 评分(字符串转浮点数)
- 年份(从“1994 (美国)”中提取数字)
- 海报链接(补全协议头)
清洗示例:
def clean_data(raw):
return {
'title': raw['title'].strip(),
'rating': float(raw['rating']),
'year': int(raw['year'].split('(')[0]),
'image': 'https:' + raw['img_url'] if raw['img_url'].startswith('//') else raw['img_url']
}
数据存储方案对比
| 存储方式 | 适用场景 | 优势 | 劣势 |
|---|---|---|---|
| CSV | 小批量、临时分析 | 无需数据库,Excel直接打开 | 无索引,并发写入冲突 |
| MySQL | 结构化、需联表查询 | 支持事务,稳定可靠 | 需预定义表结构,扩展稍慢 |
| MongoDB | 字段不固定、快速迭代 | 灵活JSON文档,水平扩展易 | 不支持复杂JOIN,内存占用大 |
本案例选择MySQL,因为电影数据字段固定且后续需要按评分排序查询。
完整爬虫存储代码拆解
以下为可直接运行的简化版代码(省略异常处理细节,可扩展频率限制):
import requests
from bs4 import BeautifulSoup
import pymysql
import re
# 第一步:建立数据库连接
conn = pymysql.connect(host='localhost', user='root', password='yourpass', db='movie_db')
cursor = conn.cursor()
cursor.execute('''CREATE TABLE IF NOT EXISTS movies (
id INT AUTO_INCREMENT PRIMARY KEY,VARCHAR(255) NOT NULL,
rating DECIMAL(3,1),
year INT,
image_url TEXT
)''')
# 第二步:爬取与解析
headers = {'User-Agent': 'Mozilla/5.0'}
for page in range(10):
url = f'https://example-movie-site.com/top250?start={page*25}'
resp = requests.get(url, headers=headers)
soup = BeautifulSoup(resp.text, 'lxml')
for item in soup.select('.movie-item'): # 实际选择器需替换
title = item.find('span', class_='title').text
rating = float(item.find('span', class_='rating').text)
year_str = item.find('span', class_='year').text
year = int(re.search(r'(\d{4})', year_str).group(1))
img = item.find('img')['src']
if img.startswith('//'):
img = 'https:' + img
# 第三步:插入数据库
sql = "INSERT INTO movies (title, rating, year, image_url) VALUES (%s, %s, %s, %s)"
cursor.execute(sql, (title, rating, year, img))
conn.commit()
cursor.close()
conn.close()
print("数据爬取并存储完成!")
性能提升:使用 executemany() 批量插入,关闭自动提交,每200条commit一次。
常见错误与优化技巧
- 错误1:连接超时 → 设置
timeout=5,加入retry装饰器 - 错误2:503反爬 → 添加随机延迟
time.sleep(random.uniform(1,3)) - 优化1:去重 → 先查已存在title,或用
INSERT IGNORE - 优化2:增量爬取 → 记录最后爬取ID,下次从该处继续
问答环节(FAQ)
Q1:爬下来的数据为什么乱码?
A:中文网站通常用 utf-8 或 gbk,解析前设置 resp.encoding = resp.apparent_encoding 自动检测。
Q2:MySQL连不上怎么办?
A:检查服务是否启动、端口(默认3306)、用户权限,可用 mysql -u root -p 命令行测试。
Q3:能否直接存到云数据库?
A:可以,只需将host改为云平台内网IP(如腾讯云的CDB),并授权白名单。
Q4:Scrapy框架比手写requests更好吗?
A:Scrapy适合大型分布式爬虫,内置去重、管道、延迟等功能;小项目手写更灵活透明。
Q5:存储大量数据怎样避免重复?
A:创建唯一索引(如电影名称+年份组合),或在插入前用SELECT count(1)校验。
延伸阅读:
- 百度云对象存储COS API文档
- 阿里云RDS MySQL读写分离配置
- 学习资源:B站“Python爬虫存储架构”系列视频
(本文综合多个技术博客与官方文档,确保步骤可复现,如需完整代码包,可关注公众号“Python数据挖掘”获取。)
标签: 存储方案