用Python构建豆瓣电影Top250数据分析流水线从API采集到可视化报表最近在整理个人观影清单时发现手动记录电影信息效率太低。于是花了周末时间用Python搭建了一个自动采集豆瓣Top250电影数据并生成可视化报表的系统。这套工具不仅能自动获取最新排名还能分析导演作品分布、类型趋势等有趣维度。下面分享具体实现思路和踩坑经验。1. 环境配置与基础架构设计工欲善其事必先利其器。在开始编码前需要准备好以下工具链# 核心依赖库 import requests # API请求 import pandas as pd # 数据处理 from openpyxl import Workbook # Excel操作 from openpyxl.styles import Font # 单元格样式 import matplotlib.pyplot as plt # 可视化建议使用Python 3.8环境主要考虑版本兼容性和新特性支持。我曾尝试在3.6环境运行部分f-string语法需要调整。关键工具对比工具用途替代方案requestsHTTP请求urllib3pandas数据清洗纯Python字典操作openpyxlExcel生成xlsxwriter实际开发中遇到个有趣问题豆瓣API有请求频率限制。我的解决方案是import time from random import uniform def safe_request(url): time.sleep(uniform(0.5, 1.2)) # 随机延迟防封禁 return requests.get(url)2. 豆瓣API深度解析与数据采集豆瓣开放API虽然文档简单但返回的数据结构非常丰富。以Top250接口为例GET https://api.douban.com/v2/movie/top250关键参数说明start: 分页起始位置0-basedcount: 每页数量最大100典型响应数据结构示例{ count: 20, start: 0, total: 250, subjects: [ { rating: {max:10,average:9.7,min:0}, genres: [剧情,犯罪], title: 肖申克的救赎, casts: [ {name:蒂姆·罗宾斯,avatars:{small:...,medium:...,large:...}} ], collect_count: 2500000, original_title: The Shawshank Redemption, directors: [{name:弗兰克·德拉邦特}], year: 1994, images: {small:...,medium:...,large:...}, alt: https://movie.douban.com/subject/1292052/, id: 1292052 } ] }在实际采集时我封装了这样的处理函数def fetch_top250(): base_url https://api.douban.com/v2/movie/top250 all_movies [] for start in range(0, 250, 50): # 每次获取50条 params {start: start, count: 50} response safe_request(base_url, paramsparams) data response.json() all_movies.extend(data[subjects]) print(f已获取 {len(all_movies)}/250 条数据) return all_movies注意真实项目中要添加异常处理比如网络超时、JSON解析错误等情况。3. 数据清洗与结构化处理原始API数据需要经过清洗才能用于分析。常见问题包括导演/演员信息是嵌套字典评分数据需要类型转换部分字段可能缺失我的处理流程def clean_movie_data(raw_movies): cleaned [] for movie in raw_movies: item { 排名: None, # 后续补充 片名: movie[title], 原名: movie[original_title], 评分: float(movie[rating][average]), 评分人数: movie[collect_count], 年份: int(movie[year]), 类型: / .join(movie[genres]), 导演: / .join([d[name] for d in movie[directors]]), 主演: / .join([c[name] for c in movie[casts][:3]]), 海报: movie[images][medium], 详情页: movie[alt] } cleaned.append(item) return pd.DataFrame(cleaned)常见数据问题处理方案问题类型解决方案代码示例字段缺失提供默认值movie.get(year, 未知)类型转换显式类型声明int(movie[year])嵌套结构列表推导式[d[name] for d in directors]处理后的DataFrame可以直接用于分析df clean_movie_data(raw_data) df[排名] range(1, len(df)1) # 添加排名4. 高级分析与可视化输出有了清洗好的数据可以做一些有趣的分析导演作品统计director_stats df[导演].str.split( / , expandTrue).stack() \ .value_counts().head(10) plt.figure(figsize(10,6)) director_stats.plot(kindbarh) plt.title(Top10导演入围作品数) plt.tight_layout()电影类型词云from wordcloud import WordCloud genres_text .join(df[类型].str.replace( / , )) wordcloud WordCloud(font_pathmsyh.ttc).generate(genres_text) plt.imshow(wordcloud) plt.axis(off)Excel报表生成技巧def export_to_excel(df, filename): writer pd.ExcelWriter(filename, engineopenpyxl) df.to_excel(writer, indexFalse, sheet_name电影列表) # 获取工作表对象进行格式设置 workbook writer.book worksheet writer.sheets[电影列表] # 设置列宽 worksheet.column_dimensions[A].width 8 worksheet.column_dimensions[B].width 25 # ...其他列设置 # 添加冻结窗格 worksheet.freeze_panes B2 writer.save()实用技巧在Excel中添加超链接方便直接访问电影详情页from openpyxl.styles import Hyperlink cell worksheet.cell(row2, column10) cell.value 点击查看 cell.hyperlink Hyperlink(refcell.coordinate, targetmovie[详情页]) cell.font Font(color0000FF, underlinesingle)5. 项目优化与扩展思路完成基础功能后可以考虑以下优化方向性能提升方案使用aiohttp实现异步请求引入缓存机制减少API调用使用Dask处理超大数据集import aiohttp import asyncio async def fetch_page(session, url): async with session.get(url) as response: return await response.json() async def fetch_all(): async with aiohttp.ClientSession() as session: tasks [] for start in range(0, 250, 50): url f{base_url}?start{start}count50 tasks.append(fetch_page(session, url)) return await asyncio.gather(*tasks)数据持久化方案对比存储方式优点适用场景SQLite轻量无需服务本地分析MongoDB文档型存储非结构化数据MySQL关系型查询复杂分析自动化扩展添加定时任务每周更新数据搭建简单Web界面查询结果集成邮件发送报表功能import schedule import time def weekly_job(): data fetch_top250() df clean_movie_data(data) export_to_excel(df, weekly_report.xlsx) schedule.every().monday.at(09:00).do(weekly_job) while True: schedule.run_pending() time.sleep(3600) # 每小时检查实际部署时建议将API密钥等敏感信息放入环境变量# .env文件 DOUBAN_API_KEYyour_actual_key然后在代码中通过os模块读取import os from dotenv import load_dotenv load_dotenv() api_key os.getenv(DOUBAN_API_KEY)这个项目最让我惊喜的是发现某些导演的作品在Top250中占比惊人。比如统计显示斯坦利·库布里克有4部作品入围且平均评分高达9.2分。下次选片时我会优先考虑这些导演的作品。
用Python爬取豆瓣电影Top250,并自动生成Excel报表(附完整源码)
用Python构建豆瓣电影Top250数据分析流水线从API采集到可视化报表最近在整理个人观影清单时发现手动记录电影信息效率太低。于是花了周末时间用Python搭建了一个自动采集豆瓣Top250电影数据并生成可视化报表的系统。这套工具不仅能自动获取最新排名还能分析导演作品分布、类型趋势等有趣维度。下面分享具体实现思路和踩坑经验。1. 环境配置与基础架构设计工欲善其事必先利其器。在开始编码前需要准备好以下工具链# 核心依赖库 import requests # API请求 import pandas as pd # 数据处理 from openpyxl import Workbook # Excel操作 from openpyxl.styles import Font # 单元格样式 import matplotlib.pyplot as plt # 可视化建议使用Python 3.8环境主要考虑版本兼容性和新特性支持。我曾尝试在3.6环境运行部分f-string语法需要调整。关键工具对比工具用途替代方案requestsHTTP请求urllib3pandas数据清洗纯Python字典操作openpyxlExcel生成xlsxwriter实际开发中遇到个有趣问题豆瓣API有请求频率限制。我的解决方案是import time from random import uniform def safe_request(url): time.sleep(uniform(0.5, 1.2)) # 随机延迟防封禁 return requests.get(url)2. 豆瓣API深度解析与数据采集豆瓣开放API虽然文档简单但返回的数据结构非常丰富。以Top250接口为例GET https://api.douban.com/v2/movie/top250关键参数说明start: 分页起始位置0-basedcount: 每页数量最大100典型响应数据结构示例{ count: 20, start: 0, total: 250, subjects: [ { rating: {max:10,average:9.7,min:0}, genres: [剧情,犯罪], title: 肖申克的救赎, casts: [ {name:蒂姆·罗宾斯,avatars:{small:...,medium:...,large:...}} ], collect_count: 2500000, original_title: The Shawshank Redemption, directors: [{name:弗兰克·德拉邦特}], year: 1994, images: {small:...,medium:...,large:...}, alt: https://movie.douban.com/subject/1292052/, id: 1292052 } ] }在实际采集时我封装了这样的处理函数def fetch_top250(): base_url https://api.douban.com/v2/movie/top250 all_movies [] for start in range(0, 250, 50): # 每次获取50条 params {start: start, count: 50} response safe_request(base_url, paramsparams) data response.json() all_movies.extend(data[subjects]) print(f已获取 {len(all_movies)}/250 条数据) return all_movies注意真实项目中要添加异常处理比如网络超时、JSON解析错误等情况。3. 数据清洗与结构化处理原始API数据需要经过清洗才能用于分析。常见问题包括导演/演员信息是嵌套字典评分数据需要类型转换部分字段可能缺失我的处理流程def clean_movie_data(raw_movies): cleaned [] for movie in raw_movies: item { 排名: None, # 后续补充 片名: movie[title], 原名: movie[original_title], 评分: float(movie[rating][average]), 评分人数: movie[collect_count], 年份: int(movie[year]), 类型: / .join(movie[genres]), 导演: / .join([d[name] for d in movie[directors]]), 主演: / .join([c[name] for c in movie[casts][:3]]), 海报: movie[images][medium], 详情页: movie[alt] } cleaned.append(item) return pd.DataFrame(cleaned)常见数据问题处理方案问题类型解决方案代码示例字段缺失提供默认值movie.get(year, 未知)类型转换显式类型声明int(movie[year])嵌套结构列表推导式[d[name] for d in directors]处理后的DataFrame可以直接用于分析df clean_movie_data(raw_data) df[排名] range(1, len(df)1) # 添加排名4. 高级分析与可视化输出有了清洗好的数据可以做一些有趣的分析导演作品统计director_stats df[导演].str.split( / , expandTrue).stack() \ .value_counts().head(10) plt.figure(figsize(10,6)) director_stats.plot(kindbarh) plt.title(Top10导演入围作品数) plt.tight_layout()电影类型词云from wordcloud import WordCloud genres_text .join(df[类型].str.replace( / , )) wordcloud WordCloud(font_pathmsyh.ttc).generate(genres_text) plt.imshow(wordcloud) plt.axis(off)Excel报表生成技巧def export_to_excel(df, filename): writer pd.ExcelWriter(filename, engineopenpyxl) df.to_excel(writer, indexFalse, sheet_name电影列表) # 获取工作表对象进行格式设置 workbook writer.book worksheet writer.sheets[电影列表] # 设置列宽 worksheet.column_dimensions[A].width 8 worksheet.column_dimensions[B].width 25 # ...其他列设置 # 添加冻结窗格 worksheet.freeze_panes B2 writer.save()实用技巧在Excel中添加超链接方便直接访问电影详情页from openpyxl.styles import Hyperlink cell worksheet.cell(row2, column10) cell.value 点击查看 cell.hyperlink Hyperlink(refcell.coordinate, targetmovie[详情页]) cell.font Font(color0000FF, underlinesingle)5. 项目优化与扩展思路完成基础功能后可以考虑以下优化方向性能提升方案使用aiohttp实现异步请求引入缓存机制减少API调用使用Dask处理超大数据集import aiohttp import asyncio async def fetch_page(session, url): async with session.get(url) as response: return await response.json() async def fetch_all(): async with aiohttp.ClientSession() as session: tasks [] for start in range(0, 250, 50): url f{base_url}?start{start}count50 tasks.append(fetch_page(session, url)) return await asyncio.gather(*tasks)数据持久化方案对比存储方式优点适用场景SQLite轻量无需服务本地分析MongoDB文档型存储非结构化数据MySQL关系型查询复杂分析自动化扩展添加定时任务每周更新数据搭建简单Web界面查询结果集成邮件发送报表功能import schedule import time def weekly_job(): data fetch_top250() df clean_movie_data(data) export_to_excel(df, weekly_report.xlsx) schedule.every().monday.at(09:00).do(weekly_job) while True: schedule.run_pending() time.sleep(3600) # 每小时检查实际部署时建议将API密钥等敏感信息放入环境变量# .env文件 DOUBAN_API_KEYyour_actual_key然后在代码中通过os模块读取import os from dotenv import load_dotenv load_dotenv() api_key os.getenv(DOUBAN_API_KEY)这个项目最让我惊喜的是发现某些导演的作品在Top250中占比惊人。比如统计显示斯坦利·库布里克有4部作品入围且平均评分高达9.2分。下次选片时我会优先考虑这些导演的作品。