1. 项目背景与核心价值
电影评分数据一直是影迷和研究者关注的重点。豆瓣作为国内最具影响力的影视评分平台之一,其Top250榜单更是汇集了全球范围内的经典佳作。这个榜单不仅反映了大众审美取向,也是研究电影市场规律的重要样本。
我最近完成了一个爬取豆瓣Top250电影数据并进行评分分析的项目。通过这个项目,不仅可以获取最新的电影排名数据,还能深入分析评分分布规律、导演作品表现等有价值的信息。整个过程涉及网络爬虫、数据清洗、统计分析等多个技术环节,对Python数据处理能力的提升很有帮助。
2. 技术方案设计
2.1 爬虫框架选择
考虑到豆瓣的反爬机制较为严格,我最终选择了Scrapy框架来实现爬虫功能。相比简单的requests+BeautifulSoup组合,Scrapy具有以下优势:
- 内置的异步处理机制能显著提高爬取效率
- 完善的中间件系统便于处理反爬策略
- 项目结构清晰,便于后期维护扩展
python复制import scrapy
from scrapy.crawler import CrawlerProcess
class DoubanSpider(scrapy.Spider):
name = 'douban_top250'
start_urls = ['https://movie.douban.com/top250']
def parse(self, response):
# 解析逻辑将在这里实现
pass
2.2 反爬应对策略
豆瓣对爬虫的防御措施包括:
- 请求频率限制
- User-Agent检测
- Cookie验证
- IP封禁机制
应对方案:
python复制# settings.py中配置
DOWNLOAD_DELAY = 3 # 请求间隔
ROBOTSTXT_OBEY = False
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...'
COOKIES_ENABLED = True
# 中间件配置
DOWNLOADER_MIDDLEWARES = {
'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None,
'scrapy_user_agents.middlewares.RandomUserAgentMiddleware': 400,
}
3. 数据爬取实现
3.1 页面解析逻辑
豆瓣Top250采用分页展示,每页25条记录。需要处理:
- 翻页逻辑
- 单页电影条目解析
- 详细信息的二次抓取
python复制def parse(self, response):
# 解析当前页电影列表
movies = response.css('.item')
for movie in movies:
item = {}
item['title'] = movie.css('.title::text').get()
item['rating'] = movie.css('.rating_num::text').get()
# 其他字段...
yield item
# 处理下一页
next_page = response.css('.next a::attr(href)').get()
if next_page:
yield response.follow(next_page, self.parse)
3.2 数据字段设计
爬取的核心数据字段包括:
| 字段名 | 说明 | 示例 |
|---|---|---|
| title | 电影名称 | 《肖申克的救赎》 |
| rating | 评分 | 9.7 |
| votes | 评价人数 | 2500000 |
| directors | 导演 | ["弗兰克·德拉邦特"] |
| year | 上映年份 | 1994 |
| country | 国家/地区 | ["美国"] |
| genres | 类型 | ["剧情","犯罪"] |
4. 数据清洗与分析
4.1 数据清洗要点
原始数据需要经过以下处理:
- 评分转换为数值类型
- 多值字段(如导演、类型)的标准化
- 缺失值处理
- 异常值检测
python复制def clean_data(df):
# 评分转换
df['rating'] = df['rating'].astype(float)
# 评价人数处理
df['votes'] = df['votes'].str.extract('(\d+)')[0].astype(int)
# 导演字段拆分
df['directors'] = df['directors'].str.split('/')
return df
4.2 评分统计分析
通过pandas进行基础统计分析:
python复制# 基础统计量
print(df['rating'].describe())
# 评分分布可视化
plt.figure(figsize=(10,6))
sns.histplot(df['rating'], bins=20, kde=True)
plt.title('豆瓣Top250评分分布')
plt.show()
典型分析维度:
- 评分区间分布
- 不同年代电影评分对比
- 导演/国家/类型维度分析
- 评分与评价人数的相关性
5. 高级分析与可视化
5.1 导演作品分析
统计导演入围Top250的作品数量及平均评分:
python复制# 展开导演列表
director_df = df.explode('directors')
# 统计导演作品
director_stats = director_df.groupby('directors').agg(
movie_count=('title', 'count'),
avg_rating=('rating', 'mean')
).sort_values('movie_count', ascending=False)
5.2 词云生成
使用jieba和wordcloud生成电影类型词云:
python复制from wordcloud import WordCloud
# 合并所有类型
all_genres = ' '.join(df['genres'].sum())
# 生成词云
wc = WordCloud(font_path='simhei.ttf',
background_color='white',
width=800, height=600)
wc.generate(all_genres)
wc.to_file('genres_wordcloud.png')
6. 项目经验与优化建议
6.1 爬取注意事项
- 请求间隔:建议设置在3-5秒,过短容易触发反爬
- 代理设置:长期运行建议使用代理池
- 异常处理:做好404等异常状态的捕获和处理
- 数据存储:建议使用MongoDB等非关系型数据库存储原始数据
6.2 分析技巧分享
- 数据标准化:不同年代的评分标准不同,可考虑按年代分组标准化
- 文本处理:导演/演员名字存在多种写法,需要统一处理
- 可视化选择:
- 评分分布:直方图+密度曲线
- 年代趋势:折线图
- 类型分析:词云+条形图
6.3 扩展方向
- 增加用户评论情感分析
- 结合票房数据研究评分与商业表现的关系
- 构建电影推荐系统
- 历史榜单变化趋势分析
这个项目最让我意外的是发现了评分与评价人数之间并非简单的正相关关系。一些超高评分的经典作品评价人数反而相对较少,这反映了影迷群体与大众观众之间的审美差异