news 2026/9/25 4:35:46

Python数据分析实战:网易云音乐歌单可视化系统完整实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python数据分析实战:网易云音乐歌单可视化系统完整实现

简介:一份基于Python数据可视化的网易云音乐歌单分析系统源码与文档说明项目资源,面向正在学习Python数据分析、需要完成课程设计或期末大作业的高校学生,特别适合用作高分大作业参考。项目完整实现了从网易云音乐歌单数据爬取、数据清洗到可视化分析的全流程,利用numpy、pandas、matplotlib、requests、jieba、wordcloud等第三方库,产出评论、收藏、播放、贡献分布数量图及词云,并给出歌单优化建议。资源共38个文件,包括12个Python源码文件、11个编译缓存pyc文件、7张结果图片、3个CSV数据文件、1个词云字体文件、1个PDF手册、1个DOCX说明文档等,压缩包约12.23MB,文件类型覆盖代码、数据、图表与文档,目录结构清晰便于对照学习。目前已有785人学习浏览,适合需要参考完整数据分析项目流程、练习爬虫与可视化技巧的读者。通过阅读源码和配套文档,可掌握数据获取、清洗、分析、可视化及报告撰写的完整思路,还能了解中文分词、词云生成、矩形树图绘制等具体实现技巧。

1. 期末大作业最常见的翻车点:图表有了,结论没了

“Python 数据分析初探项目 基于 Python 数据可视化的网易云音乐歌单分析系统”,这个标题背后其实是一个很典型的场景:你要在本学期末交出一份能拿高分的数据分析大作业,数据源选的是网易云音乐歌单,手段是 Python 数据分析与可视化,交付物是源码加文档说明。很多人的做法是下载一份歌单数据,画几张柱状图折线图,然后凑出一篇报告,最后被老师问一句“你的图表说明什么”就答不上来。

这个系统的价值不在于图表有多花哨,而在于把“从数据到结论”这条路走通:歌单的播放量、收藏量、歌曲数量、标签分布这些字段,经过清洗、聚合、可视化之后,能回答“什么样的歌单更容易被收藏”“标签和播放量有没有关系”这类具体问题。适合期末大作业、课程设计,也适合刚学完 Pandas 和 Matplotlib 想找个完整练手项目的人。本文按我实际做过的方案来拆解,从数据获取讲到图表输出,最后把遇过的坑都列出来。

2. 先把数据和字段理顺:歌单分析系统的地基

2.1 数据从哪来:接口抓取还是本地文件

做歌单分析,第一步不是写可视化代码,而是先把数据拿到手。常见做法有两种:一种是直接请求网易云的歌单接口拿 JSON,另一种是用现成的导出工具或数据集文件。对期末大作业来说,我建议优先走接口抓取,因为能体现爬虫能力,而且数据是自己抓的,答辩时经得起问。

接口抓取的思路是:歌单列表页的背后有一个分页接口,返回的 JSON 里包含歌单 ID、名称、播放量、收藏数、歌曲数、创建者等信息。请求时带一个 UA 伪装成浏览器,一般就能拿到数据。这里的关键参数是分页的 offset 和 limit,比如一次取 50 个歌单,翻页就改 offset。要注意的是,接口字段名在不同时期会变,你抓回来后先打印一条记录看结构,再决定字段映射。

我自己更常用的方式是先抓一次落盘成 JSON,后面的步骤全部基于本地文件做,避免频繁请求被限流。这样清洗、可视化、写报告可以分开跑,不会因为网络波动导致整个流程挂掉。数据量上,我一般抓 1000 到 2000 个歌单就够分析了,再多对结论帮助不大,反而可能被风控盯上。

import json import time import requests headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" } playlist_data = [] for offset in range(0, 500, 50): # 10页,每页50条,共500条 url = "https://xxx.example.com/api/playlist" # 换成实际可用的歌单接口 params = {"offset": offset, "limit": 50} resp = requests.get(url, headers=headers, params=params, timeout=10) if resp.status_code != 200: print(f"offset={offset} 请求失败,状态码 {resp.status_code}") break items = resp.json().get("playlists", []) if not items: break playlist_data.extend(items) time.sleep(1) # 控制请求频率,避免被限流 with open("playlists_raw.json", "w", encoding="utf-8") as f: json.dump(playlist_data, f, ensure_ascii=False, indent=2) print(f"抓取完成,共 {len(playlist_data)} 条歌单")

这段代码有两点值得说明。第一是sleep(1),每页请求间隔一秒,这是爬虫的基础素养,也是期末答辩时老师会问到的细节;第二是状态码判断和空列表判断,接口一旦返回异常就停,不会让程序闷头跑下去。offset单位是页内游标,每页 50 条,500 条数据意味着 offset 取 0 到 450 之间每次加 50。如果你只需要做分析演示,200 条也够,重点是后面能讲出故事。

2.2 清洗脚本:把脏数据变成能分析的 DataFrame

抓下来的 JSON 里,播放量可能是字符串“123.4万”,收藏数可能缺失,标签可能是个列表,歌曲数可能是字符串。这些不处理,后面画图全是坑。清洗步骤一般是:从 JSON 里抽出关键字段构建 DataFrame,把“万”转成数字,缺失值统一填充或丢弃,重复歌单去重,最后存成 CSV。

import pandas as pd with open("playlists_raw.json", "r", encoding="utf-8") as f: data = json.load(f) rows = [] for item in data: rows.append({ "playlist_id": item.get("id"), "name": item.get("name"), "play_count": item.get("play_count", 0), "book_count": item.get("book_count", 0), "track_count": item.get("track_count", 0), "tags": item.get("tags", []), "creator": item.get("creator", {}).get("nickname", ""), "create_time": item.get("create_time", 0), }) df = pd.DataFrame(rows) df = df.dropna(subset=["playlist_id", "name"]) df = df.drop_duplicates(subset=["playlist_id"]) def convert_wan(value): if isinstance(value, str): if "万" in value: return float(value.replace("万", "")) * 10000 return float(value) return float(value) df["play_count"] = df["play_count"].apply(convert_wan) df["book_count"] = df["book_count"].apply(convert_wan) df.loc[df["track_count"].isna(), "track_count"] = 0 df["track_count"] = df["track_count"].astype(int) df.to_csv("playlists_clean.csv", index=False, encoding="utf-8-sig") print(df[["name", "play_count", "book_count", "track_count"]].head())

这里四个操作要重点理解。dropna只针对主键字段,歌单名和 ID 为空的行没有分析价值,直接丢;drop_duplicates用歌单 ID 去重,因为分页抓取时可能遇到同一个歌单出现在不同页。convert_wan是核心转换函数,把“123.4万”拆成数字再乘 10000,这里必须写成函数而不是循环体内重复代码,因为 Pandas 的apply比遍历快一个量级。最后存 CSV 时用utf-8-sig编码,这是 Windows 下 Excel 打开不乱码的关键参数,很多人在这一步翻车。

清洗完先别急着画图,先跑一句df.describe()看分布。我一般会检查 play_count 的最大值、中位数、是否出现极端值,这决定后面可视化用线性的还是对数的坐标轴。

3. 可视化落地:让图表替你说话

3.1 图表选型:先定结论再定图

数据可视化最忌讳的是“先画一堆图再说”。正确的操作是先问自己:老师看完报告,希望你记住什么结论?对歌单分析系统来说,三个问题值得回答:播放量分布是否极端、收藏量和播放量是否相关、哪些标签的歌单更容易受欢迎。三个问题对应三张图:直方图、散点图、标签条形图。

选型逻辑也很简单:分布看直方图,相关性看散点图,排名看条形图。不要一上来就用 echarts 画炫酷的动态图,默认的 Matplotlib 足够拿高分,关键是你能不能解释清楚每个轴的含义。如果你的报告需要交互式图表,用 pyecharts 导出 HTML 是加分项,但那是后期的事,先把静态图做扎实。

3.2 三张核心图:分布、相关与排名

这三张图的代码可以放在一个脚本里,方便统一管理和复现。播放量分布图,重点看是否长尾;收藏和播放的散点图,看有没有线性关系;标签的条形图,把集中出现的标签列出来。图表标题、轴标签、网格线是评分老师最注意的细节。

import matplotlib.pyplot as plt import pandas as pd import numpy as np df = pd.read_csv("playlists_clean.csv", encoding="utf-8-sig") # 图一:播放量分布直方图 plt.rcParams["font.sans-serif"] = ["Microsoft YaHei"] plt.rcParams["axes.unicode_minus"] = False fig, axes = plt.subplots(1, 3, figsize=(16, 5)) axes[0].hist(df["play_count"], bins=50, color="#2d7dd2", edgecolor="white") axes[0].set_title("歌单播放量分布") axes[0].set_xlabel("播放量") axes[0].set_ylabel("歌单数量") axes[0].grid(alpha=0.3) # 图二:收藏量与播放量的散点图 axes[1].scatter(df["play_count"], df["book_count"], alpha=0.4, s=10, c="#d45e5e") axes[1].set_title("收藏量 vs 播放量") axes[1].set_xlabel("播放量") axes[1].set_ylabel("收藏量") axes[1].set_xscale("log") axes[1].set_yscale("log") axes[1].grid(alpha=0.3) # 图三:出现频次最高的前15个标签 from collections import Counter tag_counter = Counter() for tags in df["tags"].dropna(): for tag in tags: tag_counter[tag] += 1 top_tags = tag_counter.most_common(15) tag_names = [t[0] for t in top_tags][::-1] tag_counts = [t[1] for t in top_tags][::-1] axes[2].barh(tag_names, tag_counts, color="#3a923a") axes[2].set_title("歌单标签频次 Top15") axes[2].set_xlabel("歌单数量") axes[2].grid(axis="x", alpha=0.3) plt.tight_layout() plt.savefig("playlist_analysis.png", dpi=150, bbox_inches="tight") plt.show()

代码里有两个参数值得细说。plt.rcParams那两行是中文显示的关键,font.sans-serif设置中文字体,axes.unicode_minus解决负号显示成方块的问题;不同操作系统字体名不同,Windows 是 “Microsoft YaHei”,macOS 用 “PingFang SC”,Linux 可能要用 “WenQuanYi Zen Hei”。set_xscale("log")是第二处关键参数,歌单播放量跨好几个数量级,线性刻度会把小播放量的数据堆在原点,对数刻度才能看出分布形态。散点图的alpha=0.4处理大量点重叠时的透明度问题。

3.3 中文显示与导出:答辩现场最容易翻车的两件事

中文乱码是期末大作业里出现频率最高的 bug,没有之一。你本地跑得好好的,到答辩电脑上图表全变方块,这不是玄学,是目标机器没有你指定的中文字体。解决办法有两个:一是在代码里加一个字体探测函数,二是保存成图片而不是依赖交互窗口。我倾向于后者,savefig时指定dpi=150以上,图片直接插入报告,答辩就用这张图,不用现场重新跑。

还有一个容易忽略的点:图表文件命名不要用“图1.png”这种,用playlist_playcount_dist.png这种带语义的名字,后期写文档说明时你才知道哪张图对应哪段分析。另外bbox_inches="tight"这个参数要养成习惯,不然图表标题会被裁掉,这是 Matplotlib 新手最容易忽视的。

def setup_chinese_font(): import matplotlib.font_manager as fm candidates = ["Microsoft YaHei", "SimHei", "PingFang SC", "WenQuanYi Zen Hei"] installed = {f.name for f in fm.fontManager.ttflist} for name in candidates: if name in installed: plt.rcParams["font.sans-serif"] = [name] return plt.rcParams["font.sans-serif"] = [candidates[0]] setup_chinese_font()

这个函数的核心逻辑是:候选字体按系统优先级排列,逐个检查是否存在于当前机器,存在就用,不存在就跳过。它的价值在于,你的代码拷贝到任何一台电脑上都能自适应字体,不用改参数。这是我从“本地能跑、换机就挂”的教训里提炼出来的。

4. 避坑:网易云歌单分析里的 5 个典型问题

4.1 播放量带“万”字:排序和分析全错

现象:画条形图时,播放量 12000 的歌单排在 3.2万 前面,因为字符串排序时数字字面量小的排在前面,带“万”的根本不成数值。

原因:网易云接口返回的播放量字段在部分场景下是格式化后的字符串,比如“3.2万”,没有做转换直接进 DataFrame,Pandas 按 object 类型处理,排序和运算全部用字符串逻辑。

解决:在清洗阶段统一走函数转换,发现字符串里有“万”就替换成数字乘 10000。注意处理两种边界:纯数字字符串和带“亿”的极端值。转换完用df["play_count"].dtype确认是 float 或 int,再进入可视化和统计环节。

4.2 CSV 用 Excel 打开乱码

现象:df.to_csv("playlists_clean.csv")存完,用 Excel 打开全是乱码,但用记事本打开正常。

原因:Pandas 默认编码是 UTF-8,Excel 对 UTF-8 无 BOM 的兼容有问题。

解决:写入时指定encoding="utf-8-sig",这是带 BOM 的 UTF-8,Excel 能正确识别。同理,如果从 Excel 存 CSV 再读回 Pandas,要用encoding="gbk"或encoding="utf-8-sig"试读,大概率是两者之一。

4.3 词云图上全是“的”“了”“音乐”

现象:对歌单名称做词云,高频词全是无意义的虚词和“音乐”“歌单”这种通用词,看不出特征。

原因:没做分词过滤,或者说停用词表里没有针对网易云场景的专属词。

解决:用 jieba 分词,加载一个停用词表,至少要把“音乐”“歌单”“歌曲”“经典”“精选”这种业务里必然高频但没有区分度的词停掉。词云的 font_path 参数必须指定一个中文字体文件路径,否则中文全变方块,和图表中文乱码是一个根源。

4.4 标签字段是数组:直接计数会报错

现象:df["tags"].value_counts()报TypeError: unhashable type: 'list',或者画图时标签全部显示不出。

原因:歌单的 tags 是一个列表,比如["华语", "流行"],Pandas 没法对列表做 value_counts。

解决:用collections.Counter在外层遍历,把每个列表的元素拆开放进 Counter。这一步要在清洗阶段完成,而不是放在绘图脚本里,否则你每次画图都要重新拆一次。

4.5 接口请求频率过高被限流

现象:程序跑到第 3 页,突然连续报 403,或者返回的数据结构变了,字段名对不上。

原因:请求频率太高,服务器的风控逻辑把 IP 临时限制,或者接口升级导致字段变更。

解决:time.sleep(1)只是最低限度的礼貌,更稳的做法是每次请求前随机 sleep 0.5 到 2 秒,并且对状态码 403 做重试退避。抓到一半挂了也别慌,把已经抓到的落盘,调整参数后继续抓,不要从头再来。字段变了就直接打印返回的 JSON 前 200 字符,看新的字段名,这是排查最快的方式。

5. 让作业变成能复用的东西:脚本参数化与结论验证

期末大作业交付的“源码 + 文档说明”,很多人只做到了“能跑”,没做到“能被别人跑起来”。我最后说两个习惯,一个是把脚本从“改代码改数据”变成“改参数跑数据”,另一个是每张图都要能说出结论。

脚本参数化的做法是引入argparse,把输入文件、输出路径、图表类型作为命令行参数传进去。比如你写了三张图,就支持--chart-type hist、scatter、barh分别运行,这样别人拿到你的源码,不用看懂代码细节也能复现你的图表。

import argparse parser = argparse.ArgumentParser(description="网易云歌单分析可视化") parser.add_argument("--input", default="playlists_clean.csv", help="清洗后的CSV路径") parser.add_argument("--chart-type", choices=["hist", "scatter", "barh"], default="hist", help="图表类型") args = parser.parse_args() df = pd.read_csv(args.input, encoding="utf-8-sig") if args.chart_type == "hist": # 播放量分布图逻辑 pass elif args.chart_type == "scatter": # 收藏与播放散点图逻辑 pass elif args.chart_type == "barh": # 标签排名逻辑 pass

文档说明也是一样,README 里只写三件事:数据怎么来的、清洗脚本怎么跑、三张图各自回答什么问题。不要写大段的环境安装教程,pip install -r requirements.txt一行带过就行。数据字典可以单独放一个 CSV 示例,每个字段一行注释,比写长篇说明文档有效得多。

结论验证这步,我的检查习惯是:每张图输出后,强制自己用一句话说出“这张图证明了什么”。比如直方图显示播放量集中在 10 万以下,长尾延伸到千万级,说明歌单的马太效应很强;散点图显示收藏量随播放量增长呈亚线性,说明高播放歌单的收藏转化率反而低。说得出来的图才留在报告里,说不出来的图删掉,这是我从多次答辩里总结出来的纪律。

这套系统的天花板不在可视化效果,在于你能不能把数据分析的“分析”二字做实:提出一个问题,用数据回答它,用图表佐证它。以上是我做这类项目一路走下来的经验和习惯,希望能帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/25 4:35:16

移动机顶盒CM211-1刷机全教程:解锁晶晨S905L3的安卓自由

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/25 4:35:16

芯片测试座精确定位原理与热力电耦合控制

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/25 4:31:54

从零构建 Agent 技能体系:定义、注册、路由与避坑实战

最近被问到最多的问题,已经从"大模型能做什么"悄悄变成了"怎么让 Agent 真正把活干完"。agent-skills 这个热词在圈子里不断出现,背后的核心命题其实很朴素:大模型本质上只会生成文字,它要变成一个能操作外部…

作者头像 李华
网站建设 2026/9/25 4:30:43

ESP32驱动HUB75全彩LED点阵屏播放GIF动图实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/25 4:29:59

硬盘坏道屏蔽原理与三层实战方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/25 4:28:54

装配式钢结构别墅施工动画制作全流程解析

1. 装配式钢结构别墅施工动画的核心价值在建筑行业向工业化、智能化转型的大背景下,装配式钢结构别墅因其"环保高效、抗震性强、工期短"等显著优势,正成为住宅建设的主流选择。而施工流程动画作为可视化技术工具,正在彻底改变传统施…

作者头像 李华