用Python爬虫分析豆瓣电影Top250:除了片名,我们还能挖出哪些有趣的数据维度?
豆瓣Top250电影数据挖掘:用Python解锁隐藏的观影指南
每次打开豆瓣电影Top250榜单,我们看到的只是冰山一角——那些耳熟能详的片名和评分。但作为一个数据分析师兼影迷,我更想知道:哪些导演在这个精英俱乐部里占据最多席位?不同年代的电影在评分上是否存在显著差异?喜剧片和剧情片谁更受观众青睐?这些问题的答案都藏在数据里,等待我们用Python来发掘。
1. 数据采集:超越基础信息的爬虫策略
传统爬虫教学往往止步于获取片名和评分,但要做真正有价值的数据分析,我们需要更全面的信息维度。以下是构建完整数据集的五个关键采集点:
- 导演与主演关系网络:从每部电影页面提取导演和主演信息,构建人物合作图谱
- 多级评分数据:不仅记录当前评分,还包括评分人数、五星至一星的比例分布
- 影片元数据:国家/地区、上映年份、片长、类型标签(一部电影可能有多个类型)
- 观众反馈特征:热门短评中的高频词、短评情感倾向分析
- 奖项与荣誉:是否获得奥斯卡、三大电影节等重要奖项
import requests
from bs4 import BeautifulSoup
import pandas as pd
def get_movie_details(url):
headers = {'User-Agent': 'Mozilla/5.0'}
response = requests.get(url, headers=headers)
soup = BeautifulSoup(response.text, 'html.parser')
details = {}
# 提取导演信息
directors = [a.text for a in soup.select('a[rel="v:directedBy"]')]
details['director'] = '|'.join(directors)
# 提取类型信息
genres = [a.text for a in soup.select('span[property="v:genre"]')]
details['genre'] = '|'.join(genres)
# 提取评分分布
rating_percents = soup.select('.ratings-on-weight .rating_per')
details['rating_dist'] = '|'.join([p.text for p in rating_percents])
return details
提示:豆瓣有严格的防爬机制,建议在代码中添加随机延迟(time.sleep)并使用代理IP池,避免被封禁。
2. 数据清洗:处理电影数据的特殊挑战
原始爬取的数据往往存在各种问题,需要针对电影数据的特性进行专门处理:
多值字段拆分:一部电影可能有多个类型(如"剧情|喜剧"),需要拆分为单独的行进行分析:
def expand_genres(df):
genre_rows = []
for _, row in df.iterrows():
genres = row['genre'].split('|')
for g in genres:
new_row = row.copy()
new_row['genre'] = g
genre_rows.append(new_row)
return pd.DataFrame(genre_rows)
时间数据标准化:处理不同格式的上映日期(有些包含电影节信息):
| 原始日期 | 标准化年份 |
|---|---|
| 1994-09-10(多伦多电影节) | 1994 |
| 2008 | 2008 |
| 2010-07-16 | 2010 |
评分数据转换:将"78.3%"这样的评分分布转换为可计算的数值:
df['5_star'] = df['rating_dist'].str.split('|').str[0].str.replace('%','').astype(float)
3. 导演分析:谁在统治Top250俱乐部
通过分组统计,我们可以发现一些有趣的导演现象:
director_stats = df.groupby('director').agg({
'title': 'count',
'rating': ['mean', 'max']
}).sort_values(('title', 'count'), ascending=False)
Top5导演作品数量:
| 导演 | 作品数 | 平均评分 | 最高评分 |
|---|---|---|---|
| 宫崎骏 | 7 | 9.12 | 9.4 |
| 克里斯托弗·诺兰 | 6 | 8.98 | 9.3 |
| 史蒂文·斯皮尔伯格 | 5 | 8.82 | 9.2 |
| 王家卫 | 4 | 8.95 | 9.1 |
| 大卫·芬奇 | 4 | 8.88 | 9.0 |
导演活跃年代分布:
import seaborn as sns
import matplotlib.pyplot as plt
plt.figure(figsize=(12,6))
sns.boxplot(x='director_group', y='rating', data=df)
plt.title('不同年代导演作品评分分布对比')
plt.xticks(rotation=45)
plt.show()
4. 类型研究:哪种电影更受高端观众青睐
将电影按主要类型分类后,我们发现了一些反直觉的结果:
各类型电影评分中位数对比:
genre_rating = df.groupby('genre')['rating'].median().sort_values(ascending=False)
- 纪录片:9.1
- 音乐剧:8.9
- 历史:8.8
- 动画:8.7
- 剧情:8.6
- 科幻:8.5
- 喜剧:8.3
类型组合分析:有些类型组合特别容易出高分作品
| 类型组合 | 平均评分 | 电影数量 |
|---|---|---|
| 剧情+犯罪 | 8.9 | 23 |
| 动画+奇幻 | 8.8 | 15 |
| 科幻+惊悚 | 8.7 | 9 |
5. 时间维度:经典电影真的更好吗
分析电影上映年份与评分的关系,可以验证"老电影更好"的说法是否成立:
year_bins = [1920, 1950, 1980, 1990, 2000, 2010, 2020]
df['year_group'] = pd.cut(df['year'], bins=year_bins)
year_stats = df.groupby('year_group').agg({
'rating': ['mean', 'count']
})
年代与评分关系:
| 年代区间 | 平均评分 | 电影数量 |
|---|---|---|
| 1920-1950 | 8.9 | 8 |
| 1950-1980 | 8.8 | 32 |
| 1980-1990 | 8.7 | 28 |
| 1990-2000 | 8.6 | 45 |
| 2000-2010 | 8.5 | 72 |
| 2010-2020 | 8.4 | 65 |
6. 观众偏好:评分分布背后的秘密
通过分析五星和一星的比例,我们可以了解电影的"争议度":
df['controversy'] = df['1_star'] / df['5_star']
最具争议的Top10电影:
- 低俗小说 (争议指数0.32)
- 搏击俱乐部 (0.31)
- 发条橙 (0.30)
- 猜火车 (0.29)
- 美国往事 (0.28)
最无争议的Top5电影:
- 肖申克的救赎 (0.08)
- 这个杀手不太冷 (0.09)
- 阿甘正传 (0.10)
- 霸王别姬 (0.11)
- 辛德勒的名单 (0.12)
7. 构建个性化推荐系统
基于以上分析,我们可以建立一个简单的推荐逻辑:
def recommend_movies(user_preferences):
"""
user_preferences: 字典,包含用户偏好的类型、年代等
示例: {'genre': ['剧情', '犯罪'], 'min_year': 1990}
"""
recommendations = df.copy()
if 'genre' in user_preferences:
mask = recommendations['genre'].isin(user_preferences['genre'])
recommendations = recommendations[mask]
if 'min_year' in user_preferences:
recommendations = recommendations[recommendations['year'] >= user_preferences['min_year']]
return recommendations.sort_values('rating', ascending=False).head(10)
在实际项目中,我经常发现数据中隐藏的模式比表面现象更有价值。比如,虽然纪录片平均评分最高,但数量却很少;而数量最多的剧情片,评分分布其实非常广泛。这些洞察不仅能指导我们更好地欣赏电影,也能帮助制片方理解高端观众的品味。
更多推荐


所有评论(0)