豆瓣Top250数据分析大作业:Python爬虫+可视化完整源码与避坑指南
简介这份资源是面向高校学生与Python初学者的数据可视化课程设计完整方案围绕豆瓣电影Top250数据集展开涵盖数据采集、清洗、统计分析与图表呈现全流程适合用作毕业设计、期末大作业或课程设计的高分参考。压缩包共221个文件约14.05MB包含27个Python源码文件、32张jpg图表、16个xml配置、5套shp/dbf/shx地理数据文件以及ipynb笔记本、pdf文档、md说明和pickled_meta等Scrapy爬虫中间数据代码附有详细注释新手也能读懂。目前已有566人学习下载。资源同时提供源码、配套文档与PPT目录结构清晰部署简单下载后即可运行复现读者可据此掌握Scrapy数据抓取、pandas清洗、matplotlib与pyecharts可视化等关键技能并直接借鉴分析思路与图表设计快速完成一份导师认可的高分项目。1. 豆瓣 Top250 数据分析大作业从一份能跑通的源码说起课程设计周最怕的不是不会写代码而是打开一份别人的源码发现环境跑不起来、数据文件缺失、图表全是空白。这份 Python 数据可视化分析大作业围绕豆瓣电影 Top250 展开包含源码、文档和 PPT目录里能看到scrapy.cfg、douban_movies_analysis.iml、Filting-checkpoint.ipynb以及一组bou2_4l.dbf、World_countries_shp.dbf地理数据文件。它解决的核心问题是把爬取、清洗、统计、可视化四个环节串成一条完整链路并且每个环节都有注释新手能顺着 Notebook 的单元格一步步执行。适合正在做毕业设计、期末大作业或数据分析课程作业的同学也适合想找一个完整案例练手 pandas 和 matplotlib 的入门者。下面按实际复现顺序拆开讲重点放在参数怎么设、坑在哪。2. 环境搭建与数据文件定位先让 Notebook 跑起来2.1 依赖清单与 Python 版本选择拿到压缩包后不要急着双击 ipynb 文件。先确认 Python 版本这份项目里的.iml文件是 PyCharm 工程配置说明作者主要在 PyCharm 里开发。常见做法是用 Python 3.8 到 3.10 之间的版本太新的 3.12 在某些可视化库上会有兼容问题。核心依赖包括 pandas、numpy、matplotlib、seaborn、jieba、wordcloud、scrapy 以及处理地理数据的 geopandas 或 shapefile 读取库。安装命令建议逐条执行不要一次性全贴进终端方便定位是哪个库报错pip install pandas numpy matplotlib seaborn jieba wordcloud scrapy pip install pyshp geopandas逻辑说明前一行覆盖数据分析和中文词云后一行处理bou2_4l.dbf这类 shapefile 地理数据。参数上如果 geopandas 安装失败多半是 GDAL 依赖问题可以退而用 pyshp 只读取属性表不画地图底图。注意 wordcloud 在 Windows 上需要编译环境装不上就换pip install wordcloud --only-binary:all:。2.2 目录结构与数据文件对应关系项目里几个文件容易让人懵bou2_4l.dbf、bou2_4p.dbf、World_countries_shp.dbf是地理边界数据通常配合地图可视化使用scrapy.cfg是爬虫工程的配置文件说明数据采集环节用的是 Scrapy 框架Filting-checkpoint.ipynb从名字看是过滤清洗阶段的 Notebook 检查点TOP250_douban_movies.iml和douban_movies_analysis.iml是 IDE 模块文件不影响运行。文件/目录作用是否必须scrapy.cfgScrapy 爬虫配置入口复现爬取时需要Filting-checkpoint.ipynb数据过滤清洗 Notebook是bou2_4l.dbf / bou2_4p.dbf地理边界属性数据画地图时需要World_countries_shp.dbf世界国家边界数据画地图时需要*.imlPyCharm 工程配置否把数据文件放在与 Notebook 同级目录下或者修改代码里的读取路径。我一般会在 Notebook 开头加一段路径检查import os base os.getcwd() for f in [bou2_4l.dbf, World_countries_shp.dbf]: print(f, os.path.exists(os.path.join(base, f)))这段代码的作用是确认数据文件是否在预期位置输出 True 才继续往下跑。参数上os.getcwd()返回当前工作目录如果你在 PyCharm 里运行工作目录默认是工程根目录和 Jupyter 可能不一致这是最常见的路径翻车点。2.3 爬虫配置与数据获取的取舍scrapy.cfg存在说明项目原本包含爬取环节。但实际做作业时豆瓣对频繁请求有反爬限制直接跑爬虫很可能拿不到完整 250 条。常见做法是先检查项目里是否已经附带爬好的 CSV 或 Excel 数据文件如果有就直接用如果没有再考虑运行爬虫并且把下载延迟调大。# scrapy 配置中建议调整的参数 DOWNLOAD_DELAY 2 # 每次请求间隔2秒 CONCURRENT_REQUESTS 1 # 并发数降到1 USER_AGENT Mozilla/5.0 ... # 设置正常浏览器UA逻辑说明DOWNLOAD_DELAY控制请求间隔数值越大越安全但越慢CONCURRENT_REQUESTS降到 1 可以避免触发封禁。如果爬虫跑不通不要死磕直接用附带数据继续做分析部分作业评分看的是分析逻辑和可视化效果不是爬虫能不能跑。3. 数据清洗与特征构造把原始字段变成能分析的列3.1 缺失值与重复值处理豆瓣 Top250 的原始数据通常包含排名、电影名、导演、主演、年份、国家、类型、评分、评价人数、短评等字段。清洗第一步是去重和补缺。常见问题是同一部电影因为爬取翻页出现重复记录以及年份字段混入非数字字符。import pandas as pd df pd.read_csv(douban_top250.csv) print(原始行数:, len(df)) # 去重按电影名去重保留第一条 df df.drop_duplicates(subset[电影名], keepfirst) # 年份字段清洗提取四位数字 df[年份] df[年份].astype(str).str.extract(r(\d{4})) df[年份] pd.to_numeric(df[年份], errorscoerce) # 评分转数值 df[评分] pd.to_numeric(df[评分], errorscoerce) # 删除关键字段缺失的行 df df.dropna(subset[电影名, 评分, 年份]) print(清洗后行数:, len(df))逻辑说明drop_duplicates的subset参数指定按哪列判重keepfirst保留首次出现str.extract用正则从混杂文本里抠出四位年份errorscoerce把无法转换的值变成 NaN 而不是报错。参数上如果发现清洗后行数远少于 250说明正则或去重条件太激进需要回看原始数据格式。3.2 国家与类型字段的拆分统计原始数据里国家和类型经常是多个值挤在一格比如“美国 / 英国”或“剧情 / 爱情 / 科幻”。要统计各国家或各类型的数量必须先拆分再展开。# 拆分国家字段并统计 df[国家] df[国家].astype(str) countries df[国家].str.split(/).explode() country_count countries.str.strip().value_counts().head(10) print(country_count) # 拆分类型字段 df[类型] df[类型].astype(str) genres df[类型].str.split(/).explode() genre_count genres.str.strip().value_counts().head(10) print(genre_count)逻辑说明str.split(/)按斜杠切分返回列表explode()把列表展开成多行这样一部多国合拍的电影会在每个国家各计一次。str.strip()去掉前后空格否则“ 美国”和“美国”会被当成两个值。参数上head(10)只取前 10 个画图时避免横坐标太密集这也是热搜里常提到的“python 画图横坐标太密集”的典型解法。3.3 评分分布与年代特征构造为了后续做评分分布直方图和年代趋势折线图需要把年份分段并构造年代标签。import numpy as np # 按十年分段 bins [1930, 1950, 1970, 1990, 2000, 2010, 2020, 2030] labels [30-40年代, 50-60年代, 70-80年代, 90年代, 00年代, 10年代, 20年代] df[年代] pd.cut(df[年份], binsbins, labelslabels, rightFalse) # 评分分档 df[评分档] pd.cut(df[评分], bins[8, 8.5, 9, 9.5, 10], labels[8.0-8.5, 8.5-9.0, 9.0-9.5, 9.5以上]) print(df[[电影名, 年份, 年代, 评分, 评分档]].head())逻辑说明pd.cut按指定区间把连续值分箱rightFalse表示左闭右开避免边界值归属歧义。参数上 bins 的起点要小于数据最小值终点要大于最大值否则会出现 NaN。这一步产出的“年代”和“评分档”是后面分组聚合的基础列。4. 可视化实现六类图表与参数调优4.1 评分分布直方图与核密度曲线评分分布是最直观的图能看出 Top250 的评分集中在哪个区间。import matplotlib.pyplot as plt import seaborn as sns plt.rcParams[font.sans-serif] [SimHei] # 中文显示 plt.rcParams[axes.unicode_minus] False fig, ax plt.subplots(figsize(10, 6)) sns.histplot(df[评分], bins20, kdeTrue, axax, colorsteelblue) ax.set_title(豆瓣Top250评分分布) ax.set_xlabel(评分) ax.set_ylabel(电影数量) plt.tight_layout() plt.savefig(评分分布.png, dpi150) plt.show()逻辑说明font.sans-serif设为 SimHei 解决中文乱码Mac 用户改成Arial Unicode MSbins20控制柱子数量太少看不出分布太多显得碎kdeTrue叠加核密度曲线。dpi150保证导出图片清晰度交作业时够用。如果中文还是方框检查系统是否装了对应字体。4.2 年代趋势折线图与类型柱状图年代趋势反映不同十年入选 Top250 的电影数量变化类型柱状图看哪些类型最容易出高分片。# 年代趋势 era_count df[年代].value_counts().sort_index() fig, ax plt.subplots(figsize(10, 5)) era_count.plot(kindline, markero, axax, colorcoral) ax.set_title(各年代入选Top250电影数量) ax.set_ylabel(数量) plt.tight_layout() plt.savefig(年代趋势.png, dpi150) plt.show() # 类型分布 fig, ax plt.subplots(figsize(10, 6)) genre_count.sort_values().plot(kindbarh, axax, colormediumseagreen) ax.set_title(Top250电影类型分布Top10) ax.set_xlabel(数量) plt.tight_layout() plt.savefig(类型分布.png, dpi150) plt.show()逻辑说明sort_index()保证年代按时间顺序排列而不是按数量kindbarh画横向柱状图类型名称较长时比竖着放更易读。参数上markero让折线拐点更明显figsize根据标签长度调整类型多的时候把宽度加大。4.3 词云图与地理分布图词云用电影短评或电影名做文本输入地理图用前面提到的 dbf 文件。from wordcloud import WordCloud import jieba text .join(df[电影名].astype(str)) words .join(jieba.cut(text)) wc WordCloud(font_pathsimhei.ttf, width800, height400, background_colorwhite, max_words100).generate(words) wc.to_file(词云.png)逻辑说明jieba.cut做中文分词font_path必须指向一个支持中文的 ttf 文件否则词云全是方块。max_words100控制显示词数。地理图部分如果 geopandas 装不上可以用 pyshp 读取 dbf 属性表做国家维度的柱状图替代不必强求地图底图。提示词云图在作业 PPT 里视觉冲击力强但不要只放词云评分分布和趋势图才是分析深度的体现。5. 避坑与常见问题排查5.1 中文显示方块或乱码现象图表标题、坐标轴中文全部显示为方框。原因matplotlib 默认字体不含中文。解决在绘图前设置plt.rcParams[font.sans-serif] [SimHei]Mac 改[Arial Unicode MS]并加plt.rcParams[axes.unicode_minus] False解决负号显示问题。5.2 Notebook 路径与数据文件找不到现象FileNotFoundError提示找不到 csv 或 dbf 文件。原因Jupyter 的工作目录和文件实际位置不一致PyCharm 里运行正常但 Jupyter 报错。解决用os.getcwd()打印当前目录再用绝对路径或os.path.join拼接不要用相对路径硬编码。5.3 爬虫跑不出数据或中途中断现象Scrapy 启动后没有输出或请求被拒绝。原因请求频率过高触发限制或 UA 被识别。解决把DOWNLOAD_DELAY调到 2 以上CONCURRENT_REQUESTS设为 1设置正常浏览器 UA。如果仍然不行直接用附带数据做分析把时间花在可视化上。5.4 词云生成报字体错误现象OSError: cannot open resource或词云全是方块。原因font_path指向的字体文件不存在或路径错误。解决把 simhei.ttf 复制到项目目录用相对路径引用Windows 可以从C:\Windows\Fonts复制Mac 用/System/Library/Fonts下的中文字体。5.5 分组统计结果与预期不符现象国家或类型统计数量明显偏少。原因拆分后没有strip()去空格或者分隔符不是斜杠而是竖线。解决先打印几条原始数据看分隔符到底是什么再调整split参数拆分后统一str.strip()。6. 从作业到可展示成果PPT 图表导出与答辩技巧把 Notebook 跑通只是第一步真正交作业时还需要把图表导出成 PPT 能用的格式。我一般会在每个savefig里把dpi设到 150 到 200 之间bbox_inchestight去掉多余白边plt.savefig(评分分布.png, dpi200, bbox_inchestight, facecolorwhite)bbox_inchestight会自动裁剪图表周围空白facecolorwhite保证导出背景是白色而不是透明贴进 PPT 不会出现黑底。参数上 dpi 超过 300 文件会很大150 到 200 足够投影展示。PPT 结构建议按“数据来源 → 清洗流程 → 分析维度 → 可视化结果 → 结论”五页走。每页只放一到两张图图下面用一句话写清楚这张图说明了什么。导师最常问的问题是“你为什么选这个图表类型”和“数据清洗掉了多少条”提前把这两个答案准备好。比如评分分布用直方图是因为要看连续变量的分布形态类型分布用横向柱状图是因为类别名称长。还有一个容易被忽略的点Notebook 里的输出顺序。答辩前从头到尾 Restart Kernel 再 Run All 一遍确认没有依赖前面单元格残留变量的情况。我见过太多人本地跑得好好的换台电脑就报NameError就是因为某个变量是在已删除的单元格里定义的。从那以后我每次交作业前都强制走一遍 Restart Run All确认每个单元格都能独立依赖前文执行。希望帮到你。本文还有配套的精品资源点击获取