资讯详情

资讯详情

Python数据分析实战:网易云音乐歌单爬取与可视化全流程解析

简介这是一份基于Python数据可视化的网易云音乐歌单分析系统完整源码与文档说明面向需要完成Python数据分析与可视化期末大作业、课程设计或毕业设计的学生也适合希望快速上手数据分析项目的新手。系统中包含数据清洗、统计分析与多种可视化图表代码注释完整逻辑清晰部署简单可直接运行使用功能上覆盖歌单数据概览、维度对比与趋势展示界面简洁易操作具有较好的实际应用价值。资源包共36个文件主要包括12个Python源码文件、11个编译生成的pyc文件、7个可视化图表png、3个csv数据文件、1个字体文件、1张图片及1份Markdown说明文档压缩包整体约8.48MB目录结构规整便于阅读和二次修改。目前已有2910人学习下载适合作为高分大作业的参考模板也可在此基础上扩展个性化分析功能。1. 网易云音乐歌单分析一个把 Python 数据分析与可视化串起来的大作业选题如果你正在找 Python 数据分析与可视化的大作业题目网易云音乐歌单分析几乎是“性价比最高”的一类数据获取有现成接口分析目标明确可视化能做出五颜六色的词云和图表老师看着也直观。但真动手做的人十有八九会卡在同一个地方——不是不会 pandas而是不明白一个完整的分析系统该由哪几块拼起来。这个题目的本质不是“画几张图”而是从爬取、清洗、存储、分析到可视化的全链路工程实践。你要交付的是一套能跑通的源码和一份能讲清楚设计思路的文档说明评审重点通常落在三个点数据来源是否可靠、分析维度是否合理、可视化是否能回答具体问题。适合的人群是刚学完 pandas 和 matplotlib、想拿一个真实数据集练手的学生或者准备应对课程设计答辩的开发者。这篇文章我会按自己做这类项目时的套路把整体架构、数据获取、分析建模、可视化落地和常踩的坑一次讲透。2. 先搭整体架构数据层、分析层、展示层怎么分工2.1 数据层歌单数据从哪里来存成什么格式网易云音乐没有公开的官方 API但网页端和 App 端存在一批被广泛使用的内部接口常见做法是通过爬虫获取歌单列表、歌单详情和歌曲评论等数据。你要构建的核心数据集应该包含三个维度第一个是歌单本身的信息像歌单标题、创建者、播放量、收藏数、标签第二个是歌单里的歌曲信息包括歌曲名、歌手、专辑、时长第三个是歌曲的热度指标比如评论数、点赞数。实际写爬虫时最省事的路径是爬“歌单广场”的分类页。网易云云音乐的网页版有一个歌单广场的 URL里面的每个歌单卡片带有 ID你只需要请求歌单分类接口拿到一批歌单 ID然后依次请求每个歌单的详情页接口。数据格式建议直接存 CSV 或者 SQLiteCSV 方便 pandas 直接读取SQLite 适合数据量大了以后做去重和查询。我这里给出一段最简的爬虫骨架用 requests 请求歌单广场分类页import requests import json import pandas as pd def get_playlist_ids(category, limit20): # 歌单广场的接口offset 控制翻页limit 控制每次拉取数量 url https://music.163.com/api/playlist/list params { cat: category, # 分类比如华语、电子、ACG order: hot, # 按热度排序能拿到播放量高的歌单 offset: 0, limit: limit } headers {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)} resp requests.get(url, paramsparams, headersheaders) data resp.json() playlists data.get(playlists, []) return [{id: p[id], name: p[name], play_count: p[playCount], track_count: p[trackCount], tags: p[tags]} for p in playlists] if __name__ __main__: result get_playlist_ids(华语, 30) df pd.DataFrame(result) df.to_csv(playlist_info.csv, indexFalse, encodingutf-8-sig)这段代码有几个关键参数你要注意cat直接决定你后面的分析主题如果你抓“华语”和“电子”两个分类后面就能做分类对比分析orderhot保证你拿到的歌单有足够播放量避免一堆只有个位数播放的僵尸歌单encodingutf-8-sig是为了 Excel 打开 CSV 不乱码这点在交文档时特别重要老师大概率会用 Excel 检查你的数据文件。requests 请求这类接口时一定要带 User-Agent 头否则很容易拿到 403 响应这是爬虫里最基础也最容易翻车的点。拿到歌单 ID 后下一步是抓歌单详情里的歌曲列表。网易云的歌单详情接口会返回歌曲的 id、name、artists你把这些字段拆出来和歌单 ID 关联就能得到“歌单-歌曲”的宽表。这里建议所有表都保留歌单 ID 字段后面做关联分析时它就是主键。2.2 分析层pandas 做聚合什么指标值得算分析层是整个系统的核心也是判断你有没有真正理解“数据分析”而不是“数据展示”的关键。常见做法是围绕四个分析目标展开播放量分布、歌单标签规律、歌曲风格偏好、评论情感趋势。播放量分布用分组聚合算每个分类的平均播放量、中位数和标准差歌单标签规律是拆解 tags 字段统计哪些标签出现频率高歌曲风格偏好则需要你把歌曲的时长、歌手维度做交叉分析。实践里我用 pandas 最顺手的一条流水线是先读 CSV然后统一列名和数据格式再来处理缺失值。网易云返回的数据经常有 tags 为空列表、artists 是嵌套字典的情况所以清洗是逃不掉的一步。下面这段是我常用的清洗和聚合代码你直接可以抄进大作业里当分析模块import pandas as pd # 读取爬虫阶段保存的歌单信息 df pd.read_csv(playlist_info.csv) # 清洗删除没有 tags 的行把 tags 从字符串解析成列表 df df.dropna(subset[tags]) df[tags] df[tags].apply(eval) # 展开标签每个标签变成一行方便后续统计 tag_series df[tags].explode() tag_stats tag_series.value_counts().head(20) # 计算每个歌单的“平均每首歌播放量”这是很常见的自定义指标 df[per_track_play] df[play_count] / df[track_count].replace(0, np.nan) # 按分类统计播放量用标签的第一个作为粗粒度分类 df[main_tag] df[tags].apply(lambda x: x[0] if x else 未知) category_play df.groupby(main_tag)[play_count].agg([mean, median, count]).sort_values(mean, ascendingFalse) print(category_play.head(10))这段代码里explode()是 pandas 里把列表字段拆成多行的核心方法没有它你后面统计标签频率会很别扭。per_track_play这个字段是很多新手不会算的指标它代表歌单里每首歌的平均播放量比单纯看歌单总播放量更能反映一个歌单的“质量”写进报告里会显得你考虑问题有深度。注意replace(0, np.nan)是为了防止 track_count 为 0 时除零报错真实数据里这种脏数据很多。2.3 展示层可视化不是画完就结束要能回答分析问题展示层听起来简单但大部分大作业的减分点就在这里。很多人用 matplotlib 画了六七个柱状图每个图孤立存在没有一个统一的故事线。我一般会要求自己每张图都对应前面分析层的一个结论比如“哪个分类的平均播放量最高”对应一张横向条形图“播放量排名前 10 的歌单有什么特征”对应一张散点图加标签“标签共现关系”用词云或弦图表达。可视化的技术选型上基本的 matplotlib 完全够用但如果你想做得更专业建议用 pyecharts 来生成交互式图表尤其做词云和地图类效果时pyecharts 的 HTML 输出在答辩演示时比静态图有说服力得多。不过要注意pyecharts 生成的 HTML 文件如果里引用了 CDN 的 JavaScript 文件离线环境下打开可能白屏交作业时最好把 HTML 文件也一并打包或者用 pyecharts 的render参数把 JS 嵌入页面。展示层的最终产物应该是一个图表和文字说明相结合的 HTML 报告而不是一堆孤立的 png 图片。3. 手把手实现从爬虫到可视化报告的最小可用系统3.1 爬虫模块歌单详情与歌曲信息抓取上一章只给了抓歌单列表的代码现在要补齐详情部分否则你的数据集里只有歌单没有歌曲分析无从谈起。歌单详情接口的请求方式比列表接口稍微复杂一点需要将歌单 ID 拼到 URL 中。这里有个常见的边界坑一个歌单最多只能返回 1000 首歌曲超出部分需要分页处理但绝大多数歌单都在 100 首以内所以先不做分页也来得及。抓下来的歌曲数据要保留歌曲 ID、歌曲名、歌手名、时长这样后面才能做风格分析。def fetch_playlist_detail(playlist_id): url fhttps://music.163.com/api/v6/playlist/detail?id{playlist_id} headers {User-Agent: Mozilla/5.0, Referer: https://music.163.com/} resp requests.get(url, headersheaders) data resp.json() track_list [] for t in data.get(playlist, {}).get(tracks, []): track_list.append({ playlist_id: playlist_id, song_id: t[id], song_name: t[name], artist: t[ar][0][name] if t.get(ar) else 未知, duration_ms: t.get(dt, 0) }) return track_list这段代码里Referer头很容易被忽略但网易云的接口很大程度靠 Referer 判断请求来源不带它偶尔会拿到错误数据。t[ar]是一个歌手列表取第一个歌手虽然不严谨但对做歌单级别分析够了如果你想做得更严谨可以用/.join(artist[name] for artist in t[ar])把所有歌手都拼起来。每抓一个歌单建议 sleep 1 秒太快容易触发反爬策略这个小细节在你文档里写清楚老师会认为你考虑到了合规性问题。挨个歌单跑完详情后把所有歌曲记录合并成一个 DataFrame再存成 songs.csv。到这里你已经有一个“歌单信息表”和“歌曲信息表”两表通过 playlist_id 关联这就是一个非常标准的数据库表结构设计哪怕你只是用 CSV也要在文档里画出表关系。3.2 数据清洗与特征工程把原始数据变成分析可用的表格这一部分是整个项目里最琐碎也最体现能力的环节。爬下来的数据基本逃不过三类脏数据字段类型混乱比如播放量可能是字符串或带了“万”字单位缺失值比如歌曲信息里歌手缺失嵌套结构比如 tags 是列表但存成了字符串。处理清洗时我习惯把所有清洗步骤写在一个独立的clean.py里这样答辩时可以直接演示每一步的输入输出。def clean_play_count(value): # 网易云返回的播放量可能带万也可能在爬取时被保留成 int if isinstance(value, str): value value.replace(万, 0000).replace(., ).strip() try: return int(value) except Exception as e: return 0 def clean_songs(df_songs): df_songs[duration_min] df_songs[duration_ms] / 60000 # 歌曲时长明显异常小于1分钟或大于15分钟的可能是问题数据 df_songs df_songs[(df_songs[duration_min] 1) (df_songs[duration_min] 15)] return df_songsclean_play_count里的替换逻辑并不优雅但真实场景下你的数据可能来自不同爬虫脚本有的字段已经被转成“1.2万”这种字符串你必须适配多种格式。更稳妥的办法是在爬虫阶段就把播放量统一成 int这里保留字符串处理是为了兼容二手数据。清洗完后你还需要生成几个“特征字段”比如歌曲时长区间小于 3 分钟、3 到 5 分钟、大于 5 分钟、歌手歌曲数同为某位歌手的歌曲数量、歌单标签数量这些特征能让后续分析维度更丰富。3.3 可视化模块用 matplotlib 和 pyecharts 输出结果前端到这一步你已经可以开始画图了。我的建议是先画“探索性图表”确认结论再画“展示性图表”放进报告。探索性图表用 matplotlib 足够速度快代码简洁展示性图表用 pyecharts 输出交互图表放进 HTML 报告里。下面以“各分类歌单平均播放量对比”为例展示两种工具分别怎么实现。import matplotlib.pyplot as plt import pandas as pd # 读取前面计算好的 category_play category_play pd.read_csv(category_play.csv, index_col0) top10 category_play.head(10).sort_values(mean, ascendingTrue) plt.figure(figsize(8, 6)) plt.barh(top10.index, top10[mean], color#cc3a3a) plt.xlabel(平均播放量) plt.title(播放量最高的 10 个歌单分类) plt.tight_layout() plt.savefig(category_play_bar.png, dpi150)这段代码里sort_values(mean, ascendingTrue)是关键排序参数横向条形图必须从小到大排列否则图表看起来会很乱。dpi150是输出高清图的常用设置答辩投影时图不会糊。如果你要用 pyecharts 画同样内容的交互图核心区别在于它把数据塞进Bar类里最终输出 HTML但展示效果更直观尤其是鼠标悬浮能看到具体数值。可视化模块要想赢在答辩建议做到“一图一结论”每张图下面写一句数据洞察比如“电子类歌单平均播放量 120 万是中位数 45 万的 2.7 倍头部效应明显”这种句子才是老师想看到的分析深度而不是停留在图本身。4. 分析进阶歌单标签共现、歌曲热度与评论情绪的联动分析4.1 标签共现矩阵用中文分词和共现词频解析用户偏好当你把几千个歌单的 tags 都抓下来之后单单做“频率统计”是不够的因为 tag 和 tag 之间有关联。比如“华语”和“流行”经常同时出现“电子”和“舞曲”也强关联。要量化这种关联最直接的方法是构造“共现矩阵”。基本思路是对每个歌单的 tags 列表两两组合成一对标签统计每对标签在同一歌单中出现的次数。这个矩阵能直观看出歌单市场里的风格集聚现象。实现共现矩阵没有那么复杂但要注意组合去重的细节。如果你用 Python 的itertools.combinations它会生成不重复的组合比双重循环要干净得多而且效率高几千个歌单毫无压力。下面这段代码我放在analysis/tag_cooccur.py里import pandas as pd from itertools import combinations from collections import Counter df pd.read_csv(playlist_info_clean.csv) df[tags] df[tags].apply(eval) co_count Counter() for tags in df[tags]: # 每个歌单内两两组合比如 [华语,流行] 得到 (华语,流行) pairs combinations(sorted(set(tags)), 2) co_count.update(pairs) # 转成 DataFrame 并计算共现次数 co_df pd.DataFrame(co_count.items(), columns[tag_pair, count]) co_df[tag_a] co_df[tag_pair].apply(lambda x: x[0]) co_df[tag_b] co_df[tag_pair].apply(lambda x: x[1]) co_df co_df.drop(columns[tag_pair]).sort_values(count, ascendingFalse) print(co_df.head(20))这段代码背后的关键提醒是sorted(set(tags))先排序再组合可以保证 (华语, 流行) 和 (流行, 华语) 不会同时出现一次并且对半减半。如果你忘了去重后续统计会翻一倍会直接影响结论。分析结果中排名靠前的标签对比如“华语”“流行”出现 500 次“欧美”“电子”出现 300 次这些都可以用来回答“什么样的歌单最容易受欢迎”这个问题。这里还可以做一个衍生分析把共现次数高的标签对提取出来用 networkx 构建标签关系网络图节点大小代表标签出现次数连线粗细代表共现次数画出来放到报告里视觉冲击力很强而且评委一看就知道你做了结构层面的分析。4.2 歌曲热度分布验证“少数歌曲贡献大部分播放量”歌单分析只停留在歌单维度还不够最好拆到歌曲维度。你可以把所有歌单里的歌曲去重然后统计每首歌出现在多少个歌单中这个“歌曲被收录次数”能反映歌曲的普适程度。再结合歌曲的评论数就能画双对数坐标下的热度分布图。这里有个知识点必须有长尾分布。绝大部分歌曲只被 1 个歌单收录极少数歌曲被 100 个歌单收录这就是典型的幂律分布。代码实现上你需要先对 song 表做聚合再和评论数做关联。网易云的单曲评论数可以通过另一个接口获取但如果你不想再爬接口可以用歌曲在歌单中出现的次数作为“热度代理指标”这是完全可行并且很多论文里都这么干的。song_count songs_df.groupby(song_id).agg( playlist_count(playlist_id, nunique), song_name(song_name, first), artist(artist, first) ).reset_index() # 观察热度分布被 1 个歌单收录的歌曲占多少 one_playlist (song_count[playlist_count] 1).mean() print(f只出现在 1 个歌单中的歌曲占比{one_playlist:.1%}) # 取出被收录次数最多的前 20 首歌 top_songs song_count.sort_values(playlist_count, ascendingFalse).head(20) print(top_songs[[song_name, artist, playlist_count]])跑出来的结果几乎一定是“80% 的歌只出现在不到 3 个歌单里”这个结论特别适合放进报告的分析部分因为它说明歌单选歌有明显的头部聚集效应。你还可以把 top 20 歌曲的歌手做一次统计看哪些歌手霸榜这就能引出“歌手影响力分析”。这些衍生分析不需要额外爬数据只是对现有数据进行不同视角的透视性价比极高。4.3 评论情感分析用 SnowNLP 跑一版最简的文本判断如果你的大作业想冲击优秀加一个自然语言处理的维度会加分很多。网易云歌曲的评论区是非常好的情感分析语料很多热门歌曲评论量破万。技术上你不用上大模型直接用 SnowNLP 库就可以做中文情感分析它会返回一个 0 到 1 之间的情感得分大于 0.5 表示积极。你只需要随机抓取若干首歌的评论画一个情感得分分布图就能看出不同风格歌曲的评论情绪差异。这里注意两个坑一是 SnowNLP 底层模型是基于电商评论训练的对音乐评论的适配度有限你得在文档里主动说明这个局限性否则答辩时老师可能质疑二是抓评论的接口速度较慢建议每首歌最多抓 10 条热评就够情感分析的意义在于趋势而不是精确值。from snownlp import SnowNLP import random # comments 是之前爬取的评论列表每个元素是 歌曲名|||评论内容 def sentiment_score(text): # 简单过滤太短的评论避免无意义文本影响结果 if len(text) 5: return None s SnowNLP(text) return s.sentiments sample random.sample(comments, min(500, len(comments))) scores [sentiment_score(c) for c in sample if sentiment_score(c) is not None]采样 500 条而不是全部是必须的因为情感分析的计算成本比 pandas 聚合高非常多对全量跑百万条评论会等到怀疑人生。采样后你可以按歌曲分组看平均情感得分再把得分叠加到歌曲热度散点图上横轴是歌曲热度的对数纵轴是情感得分颜色代表风格这样一张图就把“热度、情绪、风格”三个维度串起来了。这种交叉分析也是答辩时最容易讲出彩的部分。5. 避坑手册网易云爬虫、数据清洗、可视化里最常见的翻车点5.1 请求接口报 403 或返回“验证码”页面现象是脚本跑着跑着突然开始返回一串 HTML而不是 JSON。原因很直接就是你的请求频率太高触发了平台的反爬机制。网易云音乐对于非登录状态下的匿名请求频率限制比很多人想象中严格。解决方法是每个请求之间做延时最好用time.sleep(random.uniform(1, 3))来打乱请求节奏同时务必带上完整的请求头包括Referer和User-Agent。如果你必须爬大量数据更稳妥的方式是使用 Session 登录后获取 Cookie 再爬但大作业场景下完全没有必要做得那么重。5.2 读取 CSV 时中文乱码或 tags 变成字符串现象是 DataFrame 里打印 tags 都是[[华语, 流行]]这种字符串。原因是爬虫用json.dumps存了中文标签读取时又被 pandas 转成了字符串。解决方法是读取时指定encodingutf-8对 tags 字段使用ast.literal_eval而不是eval后者有安全隐患。我见过很多同学用eval处理数据在自己电脑上没问题但代码审查时老师会问你为什么会用 eval 解析数据答案不好解释。用literal_eval更安全也更规范。5.3 播放量字段有“万”字单位导致聚合数值偏差现象是画出平均播放量的柱状图数值大得离谱比如某个分类平均播放量是 1.5 亿实际应该是 1.5 万。原因是爬虫拿到的原始字段是1.5万pandas 不会自动把“万”换算成数字直接to_numeric会报错而如果你忽略了这一列后面所有统计都会错。解决方法是保证所有的数字字段在爬虫阶段就转成纯数字或者用上一章写的清洗函数统一转换。这个坑最容易出在从网上找二手数据集来做的场景二手数据里有各种不可预知的格式拿到数据先df.info()看看字段类型是基本操作。5.4 可视化图太多但无法放进文档说明里现象是你的代码生成了 20 张 PNG但报告里放不下最后只贴了 3 张另外 17 张白做了。原因是做可视化时没有先明确每张图要回答的问题。解决方法是先列出你想在文档说明里写的 5 个问题比如“哪些标签最受欢迎”“播放量在分类之间分布差多少”然后针对每个问题只做 1 张图多做的都是浪费。这样不仅代码更短报告结构也清晰。另一个技巧是直接用一个 HTML 文件汇总所有交互图用 iframe 或 pyecharts 的多图布局把图表整合成一份报告文件提交作业时只需交付 HTML 就能完整演示。5.5 源码与文档说明脱节代码跑不通现象是文档说明里写“图 3 展示了分类平均播放量”但实际代码里根本没有生成这张图的脚本或者运行时因为文件路径不同报错。原因是写文档和写代码不同步最后仓促拼凑。解决方法是把整个项目目录设计成 tree 结构代码文件按序号命名比如01_crawl.py、02_clean.py、03_analysis.py、04_visualize.py文档说明里的每个步骤都指向对应脚本和输出文件。你还要保证项目能在运行路径下找到数据文件所以所有读取路径要使用相对路径而不是绝对路径。最后交作业前一定要把项目复制到另一台电脑上跑一遍这是最有效的防线。6. 进阶技巧把你的歌单分析系统包装成一份耐看的课程设计报告到这一步核心代码和图表都有了剩下就是怎么把这些东西组装成一份让老师打出高分的报告。先讲报告结构。不要按“做了什么模块”罗列而是按“数据来源—数据清洗—分析方法—分析结果—可视化展示—总结”这条叙事线来写。开头写清楚你这个系统解决了什么问题比如“通过分析网易云音乐歌单数据挖掘出不同风格歌曲的用户偏好与传播规律”。然后每一章先放结论再展示支撑结论的图表配合一段不超过 100 字的解读。图表和代码不要混在一起代码统一放到附录报告正文只放图和表。还有一个提升质感的技巧是做“动态报告”。用 Jupyter Notebook 写分析流程把每一步的代码、Markdown 解读和图表整合在一个.ipynb文件里最后导出成 HTML 提交。老师打开就能看到完整的分析过程还能自己改参数运行这比交付一堆零散脚本要有说服力得多。如果你愿意更花心思可以在 HTML 报告开头加一个目录导航用合适的样式指向各个图表这种细节会让你的作品看起来像一个“系统”而不是一次“作业”。另外文档说明中一定要包含“局限与改进”。写清楚你的分析是基于抽样歌单而不是全量数据情感分析用的是通用模型不是音乐场景专用模型这些诚实的表述反而会提升可信度。我习惯从行业视角看这类项目一个歌单分析系统的真正价值不是画图本身而是让运营人员能回答“我的用户到底喜欢什么”。你可以在报告最后加一个实际应用场景比如针对某个音乐电台的运营建议从数据里提炼出“深夜时段更偏好纯音乐通勤时段更偏好华语流行”这种落到具体业务的结论会让你整个系统高度立起来。最后做这类项目我自己最深的教训是一定不要等到最后两天才开始跑数据。网易云的接口稳定性、你本地机器抓 500 个歌单要花的时间、pyecharts 生成 HTML 的大小这些都会超出你预期。提前预留两天做数据采集再用一天写分析和可视化最后留半天跑通全流程并导出报告。这样不管发生什么意外你都有后悔药可以吃。希望这个方案能帮你在课程设计里少走弯路把这项大作业真正做成一个能拿得出手的作品。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →