资讯详情

网易云歌单数据分析与可视化:Python实战完整解析

📅 2026/10/10 19:52:33 | 华诺云谱 👁 阅读
网易云歌单数据分析与可视化:Python实战完整解析
简介一份基于Python数据可视化的网易云音乐歌单分析系统完整源码与文档说明面向Python期末大作业、课程设计及数据分析入门学习者。项目围绕网易云音乐歌单数据覆盖数据导入、清洗、统计分析与可视化展示全流程代码注释详细界面简洁易用下载后简单部署即可运行便于快速完成高分作业或作为实战练习。压缩包共36个文件核心为12个Python脚本另含11个pyc预编译文件、7张png图表截图、3个csv数据集、1个ttf字体及1份md说明文档整体大小8.48MB目录结构清晰便于按模块学习。目前已有2910人学习下载适用于期末答辩、课程设计或自学者模仿实现。借助该项目可掌握Pandas数据处理、Matplotlib/PyEcharts可视化等关键技能也可参考其工程组织方式将分析思路迁移到其他数据场景中。1. 网易云歌单分析期末大作业的高分选题与这份源码的结构真相如果你正在为 Python 数据分析与可视化大作业挠头又不想拿鸢尾花、泰坦尼克号这种被写了无数遍的数据集凑数网易云音乐歌单分析是个性价比很高的方向。它自带社交属性和真实业务场景评分老师一眼就能看出你不是在套模板。这份源码包我拆过里面是完整的 NeteaseCloudMusicDataAnalysis 工程含 README 和带注释的源码跑通后能输出播放量分布、歌单分类占比、标签词云、评分区间等一系列图表直接当课程设计或期末大作业交付界面和报告都撑得住场面。适合有 Python 基础、手头缺一个完整项目的在校生也适合想快速搭一套数据可视化报告模板的从业者。这篇文章我会按「数据从哪来 → 可视化怎么做 → 源码怎么拆 → 坑在哪 → 怎么加分」的顺序盘一遍新手照着跑熟手看参数看边界。2. 数据从哪来歌单接口、字段设计与清洗策略2.1 为什么选歌单而不是歌曲评论当数据源很多同学一上来就想去爬网易云热评觉得有情怀、有数据量。但评论接口的反爬强度、字段复杂度、文本清洗成本都远高于歌单接口。歌单是网易云公开数据里结构最规整的一块每个歌单有 id、名称、创建者、标签、播放量、收藏数、评论数、歌曲数这些字段天然就是为数据分析准备的。更重要的是歌单本身是一层「编辑聚合」比单首歌的信息维度高——你能从歌单标签看出用户群体的听歌口味分布能对比播放量和收藏量的关系这些都是答辩时有话可说的分析点。我一般建议数据量控制在 3001000 个歌单之间。太少图表没形状太多爬取时间和被封风险不成比例。源码里默认的采集规模就是这个量级跑一次全流程大概几十分钟期末作业完全够用。字段选得好后面所有可视化都有素材不用返工。2.2 爬取脚本骨架与接口字段说明先看数据采集这一层的核心逻辑。源码里用的是网易云网页版的歌单列表接口通过构造请求参数拉取 JSON 数据然后逐条解析歌单字段。下面这段是提取核心逻辑后的骨架import requests import pandas as pd def fetch_playlist(cat: str, limit: int 50, offset: int 0): # 网易云歌单分类接口cat 是分类名limit 是单次条数offset 是偏移量 url https://music.163.com/api/playlist/list params { cat: cat, # 分类如华语流行电子 order: hot, # 排序方式hot 表示按热度 limit: limit, # 每次返回条数建议 30~50 offset: offset # 翻页偏移offset 页数 * limit } headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64), Referer: https://music.163.com/, Cookie: appver2.0.2 # 反爬需要缺失会返回错误码 } resp requests.get(url, paramsparams, headersheaders, timeout10) data resp.json() records [] for item in data.get(playlists, []): records.append({ playlist_id: item.get(id), name: item.get(name), play_count: item.get(playCount), book_count: item.get(bookCount), # 收藏数 track_count: item.get(trackCount), # 歌曲数 comment_count: item.get(commentCount), tags: ,.join(item.get(tags, [])), creator: item.get(creator, {}).get(nickname, ), category: cat }) return pd.DataFrame(records)这段逻辑不复杂但三个参数值得你写进作业文档里。cat是网易云歌单分类体系的入口不同分类的数据分布差异很大「华语」「电子」「轻音乐」的热度曲线完全不同后期做分类对比就靠这个字段。limit我建议压在 50 以内调大了接口响应时间会陡增而且单次返回超过 100 条时网易云经常截断。order取hot意味着拿的是热门歌单样本这是一个采样偏差分析报告里要写明白你的结论描述的是「热门歌单生态」不是全部歌单。2.3 清洗规则空值、重复与标签归一化爬下来的数据千万不能直接画图这是数据分析大作业里最容易翻车的一步。网易云接口返回的数据有三个典型问题部分歌单的playCount会偶发缺失导致出现 0 值同一歌单因为分类交叉会被重复抓取tags字段里「华语」「国语」「内地」这类近义标签并存直接做词云会出现语义重叠。def clean_playlist_df(df: pd.DataFrame) - pd.DataFrame: # 1. 去掉完全重复行按 playlist_id 为准 df df.drop_duplicates(subset[playlist_id]) # 2. 播放量和收藏量为空的歌单剔除保留 0 值但标注来源 df df.dropna(subset[play_count, book_count]) # 3. 标签归一化把近义标签合并方便后面分类统计 tag_alias { 华语: 华语, 国语: 华语, 内地: 华语, 欧美: 欧美, 英语: 欧美, 日语: 日语, 韩国: 韩语, 韩语: 韩语 } def normalize(tag_str: str): parts [tag_alias.get(t.strip(), t.strip()) for t in tag_str.split(,)] # 去重但保留顺序 seen set() out [] for p in parts: if p and p not in seen: seen.add(p) out.append(p) return ,.join(out[:3]) # 每个歌单最多保留3个主标签 df[tags_norm] df[tags].apply(normalize) return df清洗要遵守一个原则宁保守勿激进。播放量为空可以直接剔除但数量为 0 的真实歌单别删那可能是新歌单能解释长尾分布。标签归一化里我没有把所有「电子」和「电音」合并因为这两个在网易云里其实是两个用户群硬合并反而抹掉了分析维度。保留前 3 个标签是为了控制维度爆炸——一个歌单挂 7 个标签的话画堆叠图时会碎成一片。做完清洗顺手把所有数值列的类型统一成int再做一次describe()输出到控制台。这一步能让你在答辩时直接说「有效样本量 847播放量中位数 12 万方差极大」比任何图表都有说服力。3. 可视化选型为什么用 pyecharts 而不是 matplotlib3.1 四类图表的选择逻辑源码里的可视化层基于 pyecharts这不是偶然。matplotlib 是传统方案稳定但图表交互性差期末答辩时老师不会凑到屏幕前放大看坐标轴pyecharts 输出的是 HTML鼠标悬停有 tooltip图表可以缩放、切换系列这种「能玩」的呈现方式在评分上的边际收益很高。我做过对比同样的数据matplotlib 画出来是「作业」pyecharts 画出来是「作品」。这套源码里核心图表有四类各有各的选型理由。播放量分布用直方图看右偏长尾歌单分类用饼图或南丁格尔玫瑰图体现占比标签词云用 WordCloud 反映热门口味播放量与收藏量关系用散点图加趋势线。这四类图覆盖了「单变量分布、占比结构、文本热度、双变量相关性」刚好对应数据分析课里最常考的四类问题。3.2 全局配置与样式定制pyecharts 的配置项很容易写乱源码里做了一层全局封装核心逻辑这样处理from pyecharts import options as opts from pyecharts.charts import Bar, Pie, Scatter def base_chart_opts(title: str): # 统一返回标题、图例和提示框配置避免每张图重复写 return ( opts.TitleOpts(titletitle, title_style{fontSize: 14}), opts.LegendOpts(type_scroll, pos_top5%), opts.TooltipOpts(triggeraxis, axis_pointer_typecross) ) def build_scatter(x: list, y: list, logx: bool False, logy: bool False): # 播放量 vs 收藏量两个坐标跨度大默认切对数轴 scatter Scatter() scatter.add_xaxis(x) scatter.add_yaxis(歌单样本, y, symbol_size6) scatter.set_global_opts( *base_chart_opts(播放量-收藏量关系), xaxis_optsopts.AxisOpts(name播放量, type_log if logx else value), yaxis_optsopts.AxisOpts(name收藏量, type_log if logy else value), datazoom_opts[opts.DataZoomOpts(range_start0, range_end100)] ) return scatter这里最关键的是type_log。播放量的实测数据从 0 到几千万线性坐标下 90% 的点会挤在左下角图等于白画。切了对数轴之后分布结构一眼就能看出来。另一个值得抄进作业的是datazoom_opts——数据量超过 300 个点以后不加数据缩放组件散点图右侧和顶部的点根本看不到分布密度。图表选型之外配色我建议源码里的默认主题先别换等结果图渲染出来再说。改主题是一个高风险动作pyecharts 换主题时字体和背景色不匹配的案例我见过太多。4. 源码包结构与核心模块拆解从抓取到报告输出4.1 包结构每个文件干什么把 zip 解开之后先别急着运行看清楚文件结构再动手。这套工程延续了 Python 数据分析项目的标准布局目录路径对了后面基本不会出幺蛾子。路径作用运行前检查main.py主入口串联采集、清洗、分析、可视化全流程确认if __name__ __main__段存在crawler.py歌单列表接口封装与分页抓取检查头部是否硬编码了过期 Cookiecleaner.py数据清洗与标签归一化确认输出为 CSV 而非直接覆盖源文件analysis.py统计指标计算分位数、分类聚合、相关系数确认数值列由int承载visualize.py全部图表的 pyecharts 构建逻辑确认输出目录output/存在README.md项目说明与运行步骤按其中要求安装依赖后再跑这套结构最聪明的点是「职责分离」。爬虫、清洗、分析、可视化各占一个文件答辩时老师问「能不能只分析已有数据不看爬虫」你可以直接跑cleaner.py之后的阶段问「换个数据源行不行」你只说改crawler.py就行。这比把一千行代码平铺在单文件里要稳得多。4.2 核心分析模块播放量分布与分类聚合的算法逻辑分析层的核心不是调用现成函数而是「知道该算什么、为什么算」。源码里analysis.py有四个统计输出我拆出来讲讲计算逻辑因为答辩时老师大概率会从这些指标切入提问。import pandas as pd import numpy as np def analyze_playlist(df: pd.DataFrame) - dict: # 输出一组统计摘要供可视化层和各答辩问题使用 stats {} # 1. 播放量分布中位数比均值更能代表典型歌单 play df[play_count] stats[play_median] int(play.median()) stats[play_mean] int(play.mean()) stats[play_p90] int(play.quantile(0.9)) # 2. 分类聚合按标签第一项聚合播放量总量 df[primary_tag] df[tags_norm].str.split(,).str[0] cat_agg df.groupby(primary_tag)[play_count].agg([count, median, sum]) cat_agg cat_agg.sort_values(sum, ascendingFalse) stats[category_table] cat_agg.head(10) # 3. 相关性播放量和收藏量取对数后再算 Pearson 系数 log_play np.log1p(df[play_count]) log_book np.log1p(df[book_count]) stats[corr_log] float(np.corrcoef(log_play, log_book)[0, 1]) # 4. 头部效应前 5% 歌单的播放量占比 top_5 play.quantile(0.95) stats[top5_share] float(df.loc[df[play_count] top_5, play_count].sum() / play.sum()) return stats播放量分布为什么不看均值看中位数因为歌单数据呈现典型的长尾分布5% 的头部歌单占了可能一半以上的播放量均值被拉高后不能代表普通歌单的真实水平中位数才是那个「一半歌单高于它、一半低于它」的稳健值。np.log1p而不是np.log是因为部分歌单播放量为 0log(0)直接报错log1p先加一再取对数既避免报错又能让 0 值映射到 0这是数据科学习惯里的标准操作。top5_share是一个答辩视角很讨巧的指标它直接量化了「马太效应有多严重」配合一句话「前 5% 的歌单占据了 63.7% 的播放量」比任何图表都直观。4.3 输出物设计图表快照与 HTML 报告分析做完不是终点报告输出才是交付物。源码里visualize.py会把所有图表 render 成 HTML 文件同时截取关键图表保存为 PNG 快照。这个双轨输出设计我很推荐HTML 用于展示和交互演示PNG 用于插入课程设计文档。from pyecharts.charts import Bar import os OUTPUT_DIR output/ def render_snapshot(chart, name: str): # 所有图表统一从这里输出带频道检查 os.makedirs(OUTPUT_DIR, exist_okTrue) chart.render(f{OUTPUT_DIR}{name}.html) # 浏览器打开后手动截图或用 snapshot 方案生成 PNG print(f[OK] {name}.html 已生成完整报告见 output/ 目录) def build_category_bar(category_table) - Bar: # 分类播放量聚合柱状图 bar Bar() bar.add_xaxis(category_table.index.tolist()) bar.add_yaxis( 累计播放量(亿), (category_table[sum] / 1e8).round(2).tolist(), label_optsopts.LabelOpts(positiontop) ) bar.set_global_opts( title_optsopts.TitleOpts(title分类播放量TOP10), xaxis_optsopts.AxisOpts(name分类, axislabel_optsopts.LabelOpts(rotate30)), yaxis_optsopts.AxisOpts(name播放量(亿)) ) return bar这里有个容易忽略的细节axislabel_opts里的rotate30。歌单分类名是「华语」「欧美」「电子」这类短词还好但如果你把primary_tag换成完整标签x 轴标签会重叠成一团黑。旋转 30 度是最稳的角度45 度又显得图表高度不够。另外把「sum」除以 1e8 再展示是为了让 y 轴单位落在「亿」而不是「987654321」这一点在报告排版时是加分项——数值可读性也是评分维度。关于 PNG 快照一个血泪经验是chart.render()只输出 HTML如果你直接用 headless 截图会有字体缺失风险。稳妥做法是交作业前手动在浏览器里打开 HTML用系统截图工具逐张保存然后把 PNG 插进 Word 文档。这份源码的 README 里也明确写了这个流程别跳过。5. 避坑指南爬虫、编码、环境依赖的五处翻车点5.1 请求被 403 拦截返回的 JSON 里没有 playlists现象运行crawler.py后打印 DataFrame 为空接口返回{code: -460}或直接 403。原因网易云的接口反爬检查了User-Agent和Referer缺失或者伪装程度不够时直接拒请求另外单 IP 高频请求也会触发限流。源码里给了基础 Header但它不是保险箱。解决把headers里的User-Agent换成浏览器「开发者工具 → Network → 复制请求头」中的真实 UA并在请求间隙加time.sleep(0.5 ~ 1.5)随机等待。我一般会让limit50的翻页循环每次随机睡 0.81.2 秒采集 800 个歌单大概多花 5 分钟但成功率从 60% 提到 95% 以上。另外把数据先落盘为 CSV 再继续后面分析爬一半崩了不用从头再来这是所有采集任务都适用的后悔药。5.2 中文乱码词云全是方块现象标签词云渲染出来文字全是方块或问号。原因pyecharts 的 WordCloud 依赖浏览器字体渲染Windows 下中文字体路径不匹配时词云组件回退到默认字体而默认字体不含中文字形。这是环境问题不是代码问题换机器也可能复现。解决在词云初始化时显式指定字体路径代码写法是WordCloud(init_optsopts.InitOpts(page_title标签词云))然后在前端模板里设置fontFamily: Microsoft YaHei。如果你把报告迁到 Linux 服务器上跑要改成WenQuanYi Zen Hei。最省事的兜底方案是词云图单独导出别和正文图混在一个 HTML 里字体重叠时单独排查。5.3 CSV 读取中文报 UnicodeDecodeError现象pd.read_csv(playlists.csv)直接抛UnicodeDecodeError或者读出来表头全乱。原因crawler.py用utf-8写盘但你在 Windows 上用 Excel 打开另存过Excel 默认会改存成gbk编码。工程混合环境工作时编码就乱了。解决读 CSV 时不要省略encoding参数按「先 utf-8失败再 gbk」的顺序尝试。代码写法def read_csv_auto(path: str): try: return pd.read_csv(path, encodingutf-8) except UnicodeDecodeError: return pd.read_csv(path, encodinggbk)这也是我在所有数据分析项目里固定的习惯。千万别在源码里写死一种编码——你永远不知道老师把文件拷到哪台机器上会做什么操作。5.4 pyecharts 版本漂移图表 API 对不上现象照着源码跑Bar().add_xaxis()报AttributeError或者opts导入失败。原因pyecharts 1.x 之后 API 做了大规模重构旧版的add()全部换成add_xaxis()加add_yaxis()。如果你以前用过 0.5.x 的老教程代码会直接翻车。源码按 1.x 写的但你的环境可能装了新版 2.x两版之间部分配置项有细微差异。解决安装依赖时把版本锁死。README 里如果要求pyecharts1.9.1就老老实实按这个装别装最新版。你要是想用新版就要做好逐个排查配置项的心理准备。血的教训我曾经图省事装最新版 2.0.x结果LabelOpts(positiontop)的渲染效果和 1.x 完全不同答辩前夜拆了半个多小时。5.5 样本量太小图表长成「三根棍」现象跑完所有图柱状图只有三两根柱子散点图稀稀拉拉词云就三个词。原因crawler.py里的limit30, offset0只抓到一页 30 个歌单分析结果没有任何统计意义。源码给的默认值偏向「快速演示」不是「完整作业」。解决把循环偏移量从offset0推到offset50*n至少抓 510 页。我建议 6 个分类各抓 100 个总计 600 个样本再进清洗流程这样每张图都有足够的形状。作业文档里要明确写「去除无效样本后有效样本量 Nxxx」这个数字会让老师默认你理解了统计分析的基本要求。6. 从交作业到加分把散落图表拼成一份可交互看板前面几步输出的是一张张独立 HTML 图数据之间没有联动。期末答辩现场老师在浏览器里逐张翻文件体验很差。源码基础上有一个性价比极高的进阶用 pyecharts 的Page组件把所有图表拼成单页看板配上Tab切换分类。这一步工作量不大但视觉效果会从「作业」直接跳到「作品」。from pyecharts.charts import Page, Tab from pyecharts import options as opts def build_dashboard(bar_chart, pie_chart, scatter_chart, word_chart): # 用 Page 实现单页滚动看板所有图表共享页面布局 page Page(layoutPage.SimplePageLayout) page.add(bar_chart, pie_chart, scatter_chart, word_chart) return page def build_tab_report(tabs_dict: dict): # 如果分类对比内容多用 Tab 分层切换适合答辩现场演示 tab Tab() for tab_name, chart in tabs_dict.items(): tab.add(chart, tab_name) return tabPage.SimplePageLayout是垂直流式排布适合播放量、分类占比这类主图如果你做了分类间对比比如「华语 vs 欧美 vs 电子」的播放量分布对比用Tab分层比全部堆在一个页面里更清晰。搭建到这一步HTML 报告打开后鼠标在散点图上悬停能看具体歌单名缩放拖拽都能操作——答辩时你可以直接说「这个散点图里右上角的点就是《深夜加班专用歌单》播放量两千万收藏八十万」这种交互式讲解比 PPT 里放截图有说服力得多。最后补一个验证习惯报告生成后我每次都会人工核对三个数——有效样本量、播放量中位数、Top5 占比确保和分析层跑出来的一致。如果这三个数对不上八成是哪一步数据处理把行数弄丢了直接回源头查清洗函数。从那以后我每次交数据类作业前都强制自己走一遍这套校验宁可多花十分钟也不带着对不上的数字进答辩现场。这份源码值不值得下取决于你想省多少时间和踩多少坑——按上面流程走一遍你收获的是一套能复用的分析框架而不只是几张图。希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑