1. 项目概述:豆瓣电影Top250爬虫实战
十年前我刚接触Python爬虫时,豆瓣电影Top250就是我的第一个实战项目。这个列表不仅记录了华语影史的经典作品,更因其清晰规整的HTML结构,成为无数爬虫学习者的"Hello World"。不同于现今复杂的反爬机制,豆瓣对Top250页面保持着相对友好的态度,既适合新手理解网页抓取的基本原理,又能满足数据采集的实际需求。
这个项目将带你用Python3.8+环境,从零实现完整的电影数据抓取流程。我们会用到requests获取网页、BeautifulSoup解析数据、csv存储结果,过程中还会涉及分页处理、异常捕获、请求间隔控制等实用技巧。最终得到的不仅是包含电影名称、评分、导演等字段的表格,更是一套可复用到其他网站的基础爬虫框架。
特别提示:虽然豆瓣对Top250页面的爬取较为宽松,但仍需遵守robots.txt规则,建议将请求间隔设置为3秒以上,避免对服务器造成压力。
2. 环境准备与工具选型
2.1 Python环境配置
推荐使用Python3.8及以上版本,这个区间的语法特性稳定且对第三方库兼容性好。如果你尚未安装Python,可以按照以下步骤操作:
- 访问Python官网下载对应系统的安装包
- 安装时务必勾选"Add Python to PATH"选项
- 安装完成后在命令行执行
python --version验证
对于开发工具,VSCode是当前最轻量高效的选择。需要安装的扩展包括:
- Python(官方扩展,提供语法高亮和调试支持)
- Pylance(微软开发的类型检查工具)
- Jupyter(方便分段执行代码)
2.2 核心库安装
在项目目录下执行以下pip命令安装依赖库:
bash复制pip install requests beautifulsoup4 lxml
各库的作用说明:
- requests:比原生urllib更人性化的HTTP请求库
- beautifulsoup4:HTML/XML解析神器
- lxml:bs4推荐的解析引擎,比内置的html.parser更快更准确
实测发现使用lxml解析豆瓣页面时,容错率比html.parser高约30%,特别对不规范的标签闭合情况处理更好。
3. 网页结构与爬虫设计
3.1 页面分析技巧
打开豆瓣电影Top250页面,按F12进入开发者工具,我们需要关注三个关键点:
-
URL规律:
- 首页:https://movie.douban.com/top250
- 分页:start参数控制偏移量(如?start=25显示26-50条)
-
数据定位:
- 每部电影包裹在
<div class="item">中 - 电影名称在
<span class="title">的第一个文本节点 - 评分位于
<span class="rating_num">
- 每部电影包裹在
-
反爬机制:
- 需要添加User-Agent头模拟浏览器访问
- 连续请求需设置合理间隔(建议3-5秒)
3.2 爬虫架构设计
完整的爬取流程应包含以下模块:
python复制def main():
# 1. 初始化数据结构
movies = []
# 2. 分页抓取
for page in range(0, 250, 25):
html = get_page(page)
parse_page(html, movies)
time.sleep(3) # 请求间隔
# 3. 存储结果
save_to_csv(movies)
这种模块化设计的好处是:
- 各功能解耦,便于单独调试
- 可扩展性强,后续添加代理等功能不影响现有逻辑
- 异常处理更有针对性(如网络请求失败只需重试get_page)
4. 核心代码实现详解
4.1 网页请求与异常处理
python复制import requests
from fake_useragent import UserAgent
def get_page(start):
url = f'https://movie.douban.com/top250?start={start}'
headers = {
'User-Agent': UserAgent().random,
'Accept-Language': 'zh-CN,zh;q=0.9'
}
try:
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status() # 检查HTTP状态码
response.encoding = 'utf-8'
return response.text
except requests.exceptions.RequestException as e:
print(f"请求失败: {e}")
return None
关键点说明:
- 使用随机UserAgent避免被识别为爬虫
- 设置超时(timeout)防止长时间无响应
- raise_for_status()自动检测400/500错误
- 显式指定编码避免中文乱码
4.2 数据解析实战
python复制from bs4 import BeautifulSoup
def parse_page(html, movies):
if not html:
return
soup = BeautifulSoup(html, 'lxml')
items = soup.find_all('div', class_='item')
for item in items:
title = item.find('span', class_='title').text.strip()
rating = item.find('span', class_='rating_num').text
info = item.find('div', class_='bd').p.get_text(strip=True)
movies.append({
'title': title,
'rating': float(rating),
'info': info.split('\n')[0] # 提取导演和主演信息
})
解析技巧:
strip=True参数自动清理空白字符- 使用CSS类选择器比XPath更易读
- get_text()比直接.text能更好处理嵌套标签
- 信息提取时注意处理换行符等特殊字符
4.3 数据存储优化
python复制import csv
from datetime import datetime
def save_to_csv(movies):
filename = f'douban_top250_{datetime.now().strftime("%Y%m%d")}.csv'
with open(filename, 'w', newline='', encoding='utf-8-sig') as f:
writer = csv.DictWriter(f, fieldnames=['title', 'rating', 'info'])
writer.writeheader()
writer.writerows(movies)
存储注意事项:
- 使用utf-8-sig编码避免Excel打开乱码
- newline=''防止Windows下出现空行
- 文件名包含日期便于版本管理
- DictWriter自动处理字典到CSV的映射
5. 高级技巧与反反爬策略
5.1 请求优化方案
基础版爬虫可能面临的问题及解决方案:
-
IP被封:
- 使用代理IP池(免费方案:https://www.zdaye.com/)
- 代码示例:
python复制proxies = { 'http': 'http://123.456.789:8888', 'https': 'http://123.456.789:8888' } requests.get(url, proxies=proxies)
-
验证码触发:
- 降低请求频率(随机间隔3-10秒)
- 模拟鼠标移动轨迹(需配合selenium)
-
数据缺失:
- 添加重试机制(最多3次)
- 使用try-catch包裹每个字段提取
5.2 数据清洗技巧
原始数据常见问题处理:
python复制# 处理别名情况(如《肖申克的救赎 The Shawshank Redemption》)
if ' ' in title:
chinese_title = title.split(' ')[0]
# 提取年份信息(从"1994 / 美国 / 犯罪 剧情"中)
year = info.split('/')[0].strip()
# 处理没有评分的电影
rating = item.find('span', class_='rating_num').text if item.find('span', class_='rating_num') else '无评分'
5.3 可视化扩展
使用matplotlib生成简单的评分分布图:
python复制import matplotlib.pyplot as plt
ratings = [m['rating'] for m in movies if isinstance(m['rating'], float)]
plt.hist(ratings, bins=10, edgecolor='black')
plt.title('豆瓣Top250评分分布')
plt.xlabel('评分')
plt.ylabel('电影数量')
plt.savefig('rating_distribution.png')
6. 常见问题与调试技巧
6.1 高频错误排查
-
返回空数据:
- 检查User-Agent是否有效
- 确认CSS选择器与当前页面结构匹配
- 打印response.text查看是否被重定向到验证页
-
中文乱码:
- 确保response.encoding='utf-8'
- 文件写入时使用utf-8-sig编码
- 避免混合使用str和bytes类型
-
连接超时:
- 增加timeout值(建议10-15秒)
- 添加retry装饰器自动重试
6.2 调试建议
-
使用IPython交互式调试:
python复制from IPython import embed embed() # 在代码中插入断点 -
分阶段验证:
- 先测试单页请求是否成功
- 再验证解析逻辑是否正确
- 最后处理分页和存储
-
日志记录:
python复制import logging logging.basicConfig(filename='spider.log', level=logging.INFO)
7. 项目扩展方向
7.1 数据深度挖掘
获取到的数据可以进一步分析:
- 导演/演员出现频率统计
- 不同类型电影的评分对比
- 年代与评分的关系趋势
7.2 技术升级路径
- 使用Scrapy框架重构项目
- 添加MySQL/MongoDB存储支持
- 实现自动化邮件报告功能
- 部署到云服务器定时运行
7.3 法律与伦理提醒
虽然电影数据属于公开信息,但需注意:
- 遵守豆瓣的robots.txt规定
- 不进行大规模并发请求
- 数据仅用于个人学习
- 不在商业场景中使用爬取结果
我在实际爬取中发现,每天抓取不超过100页、间隔大于3秒的请求,基本不会被封禁。对于关键业务数据,建议考虑豆瓣官方API(需申请权限)。这个项目更大的价值在于掌握通用的爬虫设计模式,这些技术可以迁移到其他合规的数据采集场景中。
