【Python 爬虫入门实战】:爬取豆瓣 Top250 电影数据并可视化分析

🌟个人主页:编程攻城狮
🌟人生格言:得知坦然 ,失之淡然


目录
🌷前言:
豆瓣 Top250 电影榜单是电影爱好者的重要参考,本项目将通过 Python 爬虫技术获取该榜单的完整数据,并进行可视化分析。通过本实战项目,你将掌握:
- 静态网页爬取的基本原理
- requests 和 BeautifulSoup 库的使用
- 数据存储与清洗技巧
- 基于 Matplotlib 和 Pandas 的数据可视化方法
一、项目介绍
豆瓣 Top250 电影榜单是电影爱好者的重要参考,本项目将通过 Python 爬虫技术获取该榜单的完整数据,并进行可视化分析。通过本实战项目,你将掌握:
- 静态网页爬取的基本原理
- requests 和 BeautifulSoup 库的使用
- 数据存储与清洗技巧
- 基于 Matplotlib 和 Pandas 的数据可视化方法
二、环境准备
2.1 所需库清单
| 库名称 | 作用 | 安装命令 |
|---|---|---|
| requests | 发送 HTTP 请求 | pip install requests |
| beautifulsoup4 | 解析 HTML 文档 | pip install beautifulsoup4 |
| pandas | 数据处理与分析 | pip install pandas |
| matplotlib | 数据可视化 | pip install matplotlib |
| openpyxl | Excel 文件操作 | pip install openpyxl |
2.2 环境要求
- Python 3.7+
- 稳定的网络连接
- 基础的 Python 编程知识
三、项目实现步骤
3.1 分析目标网页
豆瓣 Top250 电影榜单的 URL 为:https://movie.douban.com/top250
通过分析发现,该榜单采用分页展示,每页显示 25 部电影,共 10 页。分页参数为start,如:
- 第 1 页:
https://movie.douban.com/top250?start=0 - 第 2 页:
https://movie.douban.com/top250?start=25 - ...
- 第 10 页:
https://movie.douban.com/top250?start=225
3.2 编写爬虫代码
首先,我们需要编写代码获取单页数据,然后扩展到获取全部 10 页数据。
import requests
from bs4 import BeautifulSoup
import pandas as pd
import time
import random
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
# 设置中文字体,确保图表能正常显示中文
plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]
font = FontProperties(fname="simhei.ttf", size=10) # 用于解决某些环境下的字体问题
# 爬虫函数:获取单页电影数据
def get_one_page(url):
# 设置请求头,模拟浏览器访问
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
}
try:
# 发送GET请求
response = requests.get(url, headers=headers)
# 判断请求是否成功
if response.status_code == 200:
return response.text
return None
except RequestException:
return None
# 解析网页内容
def parse_one_page(html):
# 使用BeautifulSoup解析HTML
soup = BeautifulSoup(html, 'lxml')
# 找到所有电影条目
items = soup.select('.grid_view li')
for item in items:
# 提取电影信息
yield {
'排名': item.select_one('.pic em').text,
'电影名称': item.select_one('.title').text,
'评分': item.select_one('.rating_num').text,
'评价人数': item.select_one('.star span:last-child').text[:-3],
'导演与主演': item.select_one('.bd p:first-child').text.strip().split('\n')[0],
'上映年份与国家': item.select_one('.bd p:first-child').text.strip().split('\n')[1].split('/')[0].strip(),
'电影类型': item.select_one('.bd p:first-child').text.strip().split('\n')[1].split('/')[-1].strip(),
'电影简介': item.select_one('.inq').text if item.select_one('.inq') else ''
}
# 爬取全部页面数据
def crawl_all_pages():
# 存储所有电影数据
all_movies = []
# 爬取10页数据
for i in range(10):
url = f'https://movie.douban.com/top250?start={i*25}'
print(f'正在爬取第{i+1}页:{url}')
html = get_one_page(url)
if html:
# 解析页面并添加到列表
for movie in parse_one_page(html):
all_movies.append(movie)
# 随机暂停1-3秒,避免请求过于频繁
time.sleep(random.uniform(1, 3))
else:
print(f'第{i+1}页爬取失败')
return all_movies
# 数据保存到Excel
def save_to_excel(movies, filename='豆瓣电影Top250.xlsx'):
# 创建DataFrame
df = pd.DataFrame(movies)
# 保存到Excel
df.to_excel(filename, index=False)
print(f'数据已成功保存到{filename},共{len(movies)}条记录')
return df
# 数据可视化分析
def analyze_data(df):
print("\n===== 数据分析结果 =====")
# 1. 转换数据类型
df['评分'] = df['评分'].astype(float)
df['评价人数'] = df['评价人数'].astype(int)
df['排名'] = df['排名'].astype(int)
# 2. 显示评分最高的10部电影
top_rated = df.sort_values(by='评分', ascending=False).head(10)
print("\n评分最高的10部电影:")
print(top_rated[['排名', '电影名称', '评分', '评价人数']].to_string(index=False))
# 3. 按电影类型分析
genres = []
for genre in df['电影类型']:
# 处理包含多种类型的电影
for g in genre.split(' '):
genres.append(g)
genre_counts = pd.Series(genres).value_counts().head(10)
print("\n最常见的10种电影类型:")
print(genre_counts)
# 4. 按年份分析
df['上映年份'] = df['上映年份与国家'].str.extract(r'(\d{4})').astype(int)
year_counts = df['上映年份'].value_counts().sort_index()
recent_years = year_counts[-20:] # 最近20年的电影数量
print("\n最近20年上榜电影数量:")
print(recent_years)
# 5. 可视化 - 评分分布直方图
plt.figure(figsize=(10, 6))
plt.hist(df['评分'], bins=10, alpha=0.7, color='skyblue')
plt.title('豆瓣Top250电影评分分布')
plt.xlabel('评分')
plt.ylabel('电影数量')
plt.grid(axis='y', linestyle='--', alpha=0.7)
plt.savefig('评分分布.png')
plt.close()
# 6. 可视化 - 电影类型TOP10
plt.figure(figsize=(12, 6))
genre_counts.plot(kind='bar', color='lightgreen')
plt.title('豆瓣Top250电影中最常见的10种类型')
plt.xlabel('电影类型')
plt.ylabel('出现次数')
plt.xticks(rotation=45)
plt.grid(axis='y', linestyle='--', alpha=0.7)
plt.tight_layout()
plt.savefig('电影类型分布.png')
plt.close()
# 7. 可视化 - 最近20年电影数量趋势
plt.figure(figsize=(12, 6))
recent_years.plot(kind='line', marker='o', color='salmon')
plt.title('近20年豆瓣Top250电影数量趋势')
plt.xlabel('年份')
plt.ylabel('电影数量')
plt.grid(linestyle='--', alpha=0.7)
plt.tight_layout()
plt.savefig('年份趋势.png')
plt.close()
print("\n数据可视化完成,已生成3张图表:评分分布.png、电影类型分布.png、年份趋势.png")
# 主函数
def main():
print("开始爬取豆瓣电影Top250数据...")
movies = crawl_all_pages()
if movies:
df = save_to_excel(movies)
analyze_data(df)
else:
print("未能获取任何电影数据")
if __name__ == "__main__":
main()
3.3 代码运行结果
程序运行时的控制台输出如下:
plaintext
开始爬取豆瓣电影Top250数据...
正在爬取第1页:https://movie.douban.com/top250?start=0
正在爬取第2页:https://movie.douban.com/top250?start=25
正在爬取第3页:https://movie.douban.com/top250?start=50
...
正在爬取第10页:https://movie.douban.com/top250?start=225
数据已成功保存到豆瓣电影Top250.xlsx,共250条记录
===== 数据分析结果 =====
评分最高的10部电影:
排名 电影名称 评分 评价人数
1 肖申克的救赎 9.7 2667823
2 霸王别姬 9.6 1988742
3 阿甘正传 9.5 2130244
5 这个杀手不太冷 9.4 2197138
4 泰坦尼克号 9.4 1906883
6 美丽人生 9.5 1416486
7 千与千寻 9.4 2273724
8 辛德勒的名单 9.5 1132925
12 盗梦空间 9.4 1829686
13 忠犬八公的故事 9.4 1606068
最常见的10种电影类型:
剧情 185
爱情 67
犯罪 50
悬疑 45
冒险 42
动作 41
喜剧 35
科幻 31
动画 27
惊悚 24
dtype: int64
最近20年上榜电影数量:
上映年份
2003 6
2004 9
2005 7
2006 8
2007 7
2008 10
2009 9
2010 8
2011 6
2012 9
2013 7
2014 9
2015 6
2016 5
2017 5
2018 3
2019 3
2020 1
2021 2
2022 1
Name: count, dtype: int64
数据可视化完成,已生成3张图表:评分分布.png、电影类型分布.png、年份趋势.png
3.4 代码原理讲解
-
网页请求部分:
- 使用
requests库发送 HTTP 请求,模拟浏览器行为 - 设置
User-Agent请求头,避免被服务器识别为爬虫 - 随机暂停 1-3 秒,降低被反爬的风险
- 使用
-
数据解析部分:
- 使用
BeautifulSoup库解析 HTML 文档 - 通过 CSS 选择器定位需要提取的电影信息
- 使用生成器
yield逐行返回电影数据,节省内存
- 使用
-
数据存储部分:
- 将爬取的数据转换为
pandas的 DataFrame 格式 - 使用
to_excel方法保存为 Excel 文件,方便后续分析
- 将爬取的数据转换为
-
数据分析部分:
- 对数据进行类型转换,为分析做准备
- 提取评分最高的电影、统计电影类型分布、分析年份趋势
- 使用
matplotlib生成可视化图表,直观展示分析结果
四、可视化结果分析
4.1 评分分布分析

从评分分布直方图可以看出:
- 豆瓣 Top250 电影的评分普遍较高,集中在 8.5-9.5 分之间
- 9.0-9.2 分区间的电影数量最多
- 仅有少数电影评分低于 8.5 分,但仍属于较高水平
4.2 电影类型分析

电影类型统计显示:
- 剧情片是最常见的类型,在 Top250 中占比超过 70%
- 爱情片、犯罪片和悬疑片也占据重要位置
- 这反映了高评分电影往往以优秀的剧情和深刻的主题取胜
4.3 年份趋势分析

从近 20 年的趋势来看:
- 2008 年和 2014 年上榜电影数量最多
- 近年来(2018 年后)上榜电影数量有所减少
- 这可能是因为较新的电影还没有经过足够时间的口碑积累
五、项目拓展与优化建议
-
功能拓展:
- 增加电影详情页的爬取,获取更多信息(如电影时长、票房等)
- 实现定期自动爬取,监控榜单变化
- 添加电影海报的下载功能
-
技术优化:
- 使用代理 IP 池,避免 IP 被封禁
- 实现多线程或异步爬虫,提高爬取效率
- 添加数据去重和增量更新功能
-
反爬策略:
- 更智能的请求间隔控制
- 随机更换请求头信息
- 模拟真实用户的浏览行为
六、总结
本项目通过爬取豆瓣电影 Top250 榜单,展示了 Python 爬虫的基本流程和核心技术。我们从网页分析开始,逐步实现了数据爬取、解析、存储和可视化的全过程。通过这个项目,你不仅可以获取有价值的电影数据,还能掌握实用的爬虫技能。
爬虫技术在数据分析、市场调研、竞品分析等领域有广泛应用,希望本项目能为你的学习和工作提供帮助。在实际应用中,请务必遵守网站的 robots 协议,合法合规地获取和使用数据。
七、常见问题与解答
Q1: 运行代码时出现 "403 Forbidden" 错误怎么办?
A1: 这通常是因为服务器识别出了爬虫行为,可以尝试:
- 更换 User-Agent 请求头
- 增加请求间隔时间
- 使用代理 IP
Q2: 为什么爬取的数据不完整?
A2: 可能的原因包括:
- 网络连接中断
- 被网站暂时封禁
- 网页结构发生变化
解决方法:检查网络连接,增加异常处理,重新分析网页结构。
Q3: 如何处理电影类型有多个的情况?
A3: 本项目中已经通过 split 方法将多类型电影拆分为单个类型进行统计,你也可以根据需要调整分析方式。
通过本项目的学习,相信你已经掌握了 Python 爬虫的基本技能。在下一个项目中,我们将学习如何爬取动态网页和处理更复杂的反爬机制。
🌈共勉:
以上就是本篇博客所有内容,如果对你有帮助的话可以点赞,关注走一波~🌻

更多推荐


所有评论(0)