ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

用Python分析Spotify听歌记录:从API到可视化实战指南

用Python分析Spotify听歌记录:从API到可视化实战指南 1. 内容整体设计与思路拆解1.1 这个标题背后到底能做什么先说结论用Python分析Spotify的听歌记录是所有数据爱好者最容易上手的练手项目之一。原因很简单——数据是现成的接口是官方的代码量不大但能挖出的信息量却非常惊人。我自己第一次跑通这个项目时光是把三年多的流媒体播放记录装进程序就发现了几件从来没注意过的事某些凌晨两点还在循环播放的冷门歌某位歌手突然在某个月占据了我80%以上的播放份额还有一首我完全不记得的歌居然单曲循环过40多次。这些数据Spotify都悄悄记着只是平时不会主动展示给你。这个项目适合谁三类人一是想学Python但苦于没有实战数据的初学者借这个项目能把pandas、request、可视化全家桶过一遍二是深度音乐用户想知道自己的收听习惯到底是什么样的三是准备往数据方向转型的从业者这比对着网上下载的电商订单假数据做分析要有意思得多因为你对每一项产出都有切身的直觉去验证和纠错。1.2 为什么选择Python来做这件事选Python不是跟风是真的合适。整个分析链路从数据拉取、清洗、计算到可视化Python都有对应的成熟库而且语法上对新手非常友好。如果换用Java或C请求API写起来要啰嗦好几倍如果用R可视化虽然好看但通用性差一些处理API请求也不如Python顺手。更重要的是生态。Spotify官方提供了Python专用的客户端库spotipy底层封装了OAuth授权、token刷新、API请求这些繁琐流程。这意味着你不需要手写一整套HTTP授权逻辑几十行代码就能拿到自己账号下所有可公开访问的数据。配合pandas做表格处理、matplotlib和seaborn做图表整个分析闭环一气呵成。在这套流程里核心数据来源有三类Recently Played接口获取最近50条播放记录适合做实时行为分析。Top Artists / Top Tracks接口获取一段时间内的热门歌手和热门歌曲支持3个月、6个月、长期三档。用户导出的扩展播放历史Spotify允许用户在账号设置里申请下载全部历史数据拿到的是一个包含多年播放记录的JSON文件这才是做深度分析的重头戏。三者互为补充组合起来就是一个完整的分析体系。1.3 两类数据源的取舍快速验证与长期统计我在实际项目中强烈建议两条路都走但先后顺序要注意。先用Spotify API拿到最近播放记录做快速验证确认授权、请求、解析基础链路没问题再申请完整的数据导出做长期趋势分析。这两类数据最大的区别在于覆盖范围和时效性。API能拿到的数据非常有限最近播放只有50条Top列表也只是汇总结果拿不到时间线。而导出数据是一个庞大的压缩包里面包含从你注册Spotify起每一天、每一首歌、每一次播放、每一分钟的明细记录包括播放时间、曲目名、艺人名、专辑名、当时使用的设备、播放结束时的进度秒数甚至包括曲目的完整Spotify链接。拿到这样的数据后你几乎可以复现出任何主流的听歌报告。比如周杰伦在某个夏天的傍晚是不是被反复点播通勤时段你更倾向于听播客还是音乐新歌发布后你会在第几天开始循环它。这些问题的答案全部藏在时间戳和曲目ID的交叉组合里。有一点要说清楚Spotify的数据导出不是实时的提交申请后可能需要几天时间才会收到邮件。官方说最多30天实际我遇到的情况通常是1到2天。本着把最不可控的环境问题提前解决的原则应该以提交数据导出申请为项目第一步然后利用等待时间走API那套链路。2. 核心细节解析与实操要点2.1 环境准备需要的Python库和版本考量不论你是macOS、Windows还是LinuxPython版本建议3.9及以上。下面这几个库是本项目的核心依赖建议统一安装最新版spotipySpotify官方API的Python SDK负责OAuth授权流程和数据请求。pandas读入JSON、清洗数据、做数据透视和聚合运算。numpy数值计算。matplotlib/seaborn图表绘制与样式美化。jupyter或ipython推荐使用Jupyter Notebook做交互式探索因为数据分析的调试过程需要频繁地分步查看中间结果。安装命令一行搞定pip install spotipy pandas numpy matplotlib seaborn jupyter如果你用的是Anaconda环境考虑用conda install统一管理依赖避免系统级Python环境被搞乱。这里有个小坑我踩过spotipy对Python 3.8以下版本的支持有问题安装后运行时会报dataclasses相关的导入错误所以先确认python --version的结果再动手。2.2 Spotify开发者账号注册与权限申请最容易卡住的第一步在写任何代码前需要先到Spotify的开发者后台创建一个应用。这一步几乎每个人都会卡一下因为流程里的术语不太直观。操作路径是登录Spotify网页版开发者后台点击Dashboard登录后点击Create app。填应用名称、描述、重定向URI这三个字段。Redirect URI对本地调试来说填http://localhost:8888/callback即可这是spotipy库的默认回调地址也可以填http://localhost:8080。填写普通的本机回环地址都是允许的。创建完成后应用页面会显示两串关键字符Client ID和Client Secret。这俩就是你的API身份凭证。最后一步记得在应用设置里的Edit Settings页面把Redirect URI加入白名单否则授权时会一直报错。权限方面不同的API端点需要不同的scope。分析个人听歌数据需要声明的scope主要有user-read-recently-played读取最近播放记录。user-top-read读取热门歌手和歌曲。user-read-playback-state和user-read-currently-playing获取当前播放状态。如果只是拿导出数据分析其实不需要任何API权限但为了完整流程建议把上面几个scope都填上。授权时会看到一个页面提示此应用将访问你的部分数据点同意即可。这里强调一下Spotify官方不显示请求的scope列表在你勾选时代码里声明什么它就请求什么心里要有数。2.3 数据导出的申请流程最应该早早启动的环节我常说分析Spotify数据最影响体验的瓶颈不是代码而是等待。数据导出的申请入口在账号设置里进入Account找到Privacy settings在Download your data一栏点Request。提交后会收到一封确认邮件。这里有个细节数据文件是按模块生成的不一定一次给全。比如Extended streaming history是主分析素材另外还有Search history、听歌付费账单模块等。使用的话重点找名为StreamingHistory0.json或Audio_Streaming_History系列的文件那种带数字序号的JSON才是播放明细。有些用户可能申请多次导致收到多个分片文件比如StreamingHistory0.json、StreamingHistory1.json内容是按时间切分的。处理时要把它们合并成一个DataFrame别只看一个文件——我曾见过有人把第0号文件当成全部历史结论错得离谱。2.4 理解JSON结构分析前的数据结构认知拿到StreamingHistory文件后第一件事是查看它的内部结构。这个文件是一个JSON数组每条记录格式如下{ endTime: 2024-05-21 15:32, artistName: 坂本龙一, trackName: Merry Christmas Mr. Lawrence, msPlayed: 312000 }字段少得有点令人意外但足够完成大部分分析。endTime是播放结束时间不是开始时间msPlayed是实际播放的毫秒数。要注意这里的播放量既包括完整播完的曲子也包括只听半截就切歌的记录。真实数据中还会出现一个额外的坑trackName字段偶尔会出现单曲版、Live版、(Remastered)这样的后缀统计时如果不做归一化同一首歌会被拆成好几个条目。后面我会给出具体的处理方案。3. 实操过程与核心环节实现3.1 通过Spotify API获取最近播放记录先放上一段可以直接运行的脚本框架。这段代码负责授权并拉取最近50条播放记录import spotipy from spotipy.oauth2 import SpotifyOAuth CLIENT_ID 你的Client ID CLIENT_SECRET 你的Client Secret REDIRECT_URI http://localhost:8888/callback sp spotipy.Spotify(auth_managerSpotifyOAuth( client_idCLIENT_ID, client_secretCLIENT_SECRET, redirect_uriREDIRECT_URI, scopeuser-read-recently-played user-top-read, cache_handlerspotipy.cache_handler.CacheFileHandler( username你的用户名 ) )) recent sp.current_user_recently_played(limit50) for item in recent[items]: track item[track] played_at item[played_at] print(f{played_at} | {track[artists][0][name]} | {track[name]})运行后浏览器会自动弹出一个授权页面登录Spotify账号同意授权后会跳转到本地回调地址然后命令行窗口就会输出最近播放的歌曲清单。这个过程中需要注意的细节是缓存。spotipy会把token缓存到本地文件.cache-你的用户名缓存有效期内不会重复弹出授权页面。如果授权信息过期想重新授权删除缓存文件再运行一次即可。3.2 读取并合并历史导出文件从JSON到DataFrame接下来处理数据导出的大文件。一个多年的播放记录文件往往有几万到几十万行直接用Excel打开会卡死pandas处理则很轻松。import pandas as pd import glob files glob.glob(StreamingHistory*.json) dfs [pd.read_json(f) for f in files] df pd.concat(dfs, ignore_indexTrue) print(f总记录数: {len(df):,}) print(df.head())如果文件路径里有中文Windows平台偶尔会报编码错误统一用encodingutf-8阅读。pd.read_json对标准JSON的解析能力足够健壮不用手动处理嵌套结构。此时做一个初始清洗msPlayed是播放时长可以换算成分钟列endTime是字符串要转成datetime类型。df[endTime] pd.to_datetime(df[endTime]) df[minutes] df[msPlayed] / 60000.0由此我们可以开始第一层统计。比如算出总收听时长、最常听的歌手、最常听的曲目、一天中哪个时段听得最多。这些都是投入产出比最高的分析点。3.3 解析播放状态API写一个当前正在收听的实时面板除了历史数据我们还可以利用API实现在线状态查询。例如写一个简短的Python脚本每隔10秒刷新一次当前播放状态输出正在播放的歌名和艺人import time while True: current sp.current_user_playing_track() if current and current[is_playing]: track current[item] progress current[progress_ms] / 60000 duration track[duration_ms] / 60000 print(f正在播放: {track[name]} - {track[artists][0][name]} f({progress:.1f}/{duration:.1f}分钟)) else: print(当前没有在播放音乐) time.sleep(10)这个脚本本质是一个监听器但它很依赖你在真实设备上的播放状态。如果你用的不是Spotify而是别的播放器这个功能就无法工作。这个限制在文档里不会明说但在实际应用中很容易踩到。3.4 深入分析维度从聚合统计到时间序列有了干净的数据就可以做几个真正有洞察力的分析。收听集中度分析。计算每个歌手的播放占比并用累计占比画出帕累托图。比如我自己的数据呈现出典型的二八定律不到10%的歌手贡献了超过60%的播放时长。artist_stats df.groupby(artistName)[msPlayed].sum().sort_values(ascendingFalse) artist_stats[cum_percentage] artist_stats.cumsum() / artist_stats.sum() * 100 print(artist_stats.head(20))时段活跃分析。按小时的周期做热力图能直观看出自己是早上通勤听得久还是睡前听得久。把一天24小时和星期几两个维度组合起来。df[hour] df[endTime].dt.hour df[weekday] df[endTime].dt.dayofweek # 0周一 heatmap_data df.pivot_table(indexweekday, columnshour, valuesmsPlayed, aggfuncsum, fill_value0)这里用pivot_table比groupby更直观它直接返回一个宽表格式拿来画热力图几乎不需要再加工。有一点小提醒这里的endTime是播放结束时间凌晨0点前后的数据会归属到当天末尾可能导致边界小时的数据波动分析时要留意。年度对比分析。导出数据的时间跨度覆盖多年按年份汇总就能看出自己的音乐口味变化轨迹。比如各年份主听歌手的更替、播放总量的升降。3.5 可视化把数据变成能讲故事的图表可视化的核心不是炫技而是让规律肉眼可见。推荐三张图组合使用。第一张是歌手总播放时长条形图。取Top 15歌手用seaborn的barplot画出水平条形图横轴卡播放分钟数。顺序按从高到低排列观察分布形状。import seaborn as sns import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False top_artists df.groupby(artistName)[minutes].sum().nlargest(15).sort_values() plt.figure(figsize(10, 8)) sns.barplot(xtop_artists.values, ytop_artists.index, huetop_artists.index, paletteviridis, legendFalse) plt.xlabel(累计播放时长(分钟)) plt.title(最常听的Top 15歌手) plt.tight_layout() plt.show()中文字体在Linux服务器上经常显示成方框需要在系统里安装中文字体包。macOS上改[Arial Unicode MS]即可Windows上用SimHei。第二张是每日播放量时间序列图。横轴是日期纵轴是每天播放总时长。这个图能一眼识别出间歇性爆发式听歌的日期通常是换工作、搬家、考试周前后。对时间序列顺手做一次滚动平均比如7天窗口更能看出长期趋势。第三张是一天24小时的播放热度热力图。按星期几和小时组合颜色越深代表播放总时长越高。这几乎是所有朋友看到都想问怎么做到的一张图因为它新颖且有真实数据支撑。可视化的经验是先把统计结果跑出来再挑最想讲的故事配图。不要一开始就追求花哨柱状图和折线图已经能覆盖90%的需求。4. 常见问题与排查技巧实录以下是实际使用中反复出现的问题整理成速查表能省掉大量排查时间。问题现象可能原因排查与解决办法授权页面一直报redirect_uri_mismatch回调地址没有加入白名单到开发者后台把实际使用的URI完整填入白名单请求时报No token providedtoken缓存过期或未保存删除.cache-用户名文件后重新运行返回的播放记录只有50条且重复Recently Played接口本身就是有限拉取改用数据导出文件做长期分析中文歌手名显示为方块matplotlib缺少中文字体设置plt.rcParams[font.sans-serif]为系统已装中文字体msPlayed为0的记录很多歌曲刚播放几秒就被切走或缓存未刷新默认msPlayed 30000(30秒)的记录可视为跳过分析时酌情过滤JSON文件读取报错Expecting value文件损坏或编码异常用二进制方式打开检查文件头部是否含BOM多个StreamingHistory文件时间有重叠不同导出批次的数据范围重叠用drop_duplicates(subset[endTime, trackName, artistName])去重4.1 过滤无效数据到底要不要删掉短播放记录这是很多人纠结的问题。播放不足10秒的歌严格来说没有消费意义统计时会拉低平均播放时长也会让最常听歌曲的排序失真。我的处理方案是valid_df df[df[msPlayed] 10000].copy()保留10秒以上的记录。如果做的是跳过率分析——即统计每次播放数据里短播放的比例那保留全部数据反而有用。也就是说过滤策略取决于你想回答什么问题没有绝对标准答案。这里我建议在初版分析中直接用全量数据先感受原始分布再决定是否清洗。4.2 时区问题为什么我的歌曲归到了错误的日期endTime字段的时区是UTC还是本地时间这个事儿官方文档写得不清楚只有实际操作才能确认。就我的数据来看字符串里不带时区信息读取为本地时间即可。但要小心如果你的电脑系统时区不是本地的pd.to_datetime解析出来后的时辰会对不上。保险做法是显式指定时区df[endTime] pd.to_datetime(df[endTime]).dt.tz_localize(UTC).dt.tz_convert(Asia/Shanghai)其实这个操作用在带时区信息的数据上是必须的对不带时区的数据要小心强行设置可能导致双倍偏移。务实一点的建议先跑一下df[hour]的分布看看是否和你真实的作息峰值吻合如果不吻合再检查时区设置。4.3 刷播放数据导致的异常值处理不管是否直接相关说一个真实现象。只要Spotify账号播放过快、大量跳过服务器端可能会把某些播放记录记成0毫秒。这类脏数据会让整体播放时长缩水。可以按设备维度分组查看某些设备比如车载音响经常出现断连导致播放时长波动大。把明显异常的1秒播放结束记录打上标记做删除或单独统计都是合理操作。4.4 性能优化几十万条数据怎么跑得快当数据量超过10万条pandas的groupby仍然很快但apply如果写不好会卡很长时间。几个实际优化习惯用category类型压缩低基数字段比如artistName和trackName。尽量用向量化运算替代逐行iterrows。聚合测试时先sample(10000)跑通逻辑再全量运行。如果多次实验把清洗好的中间结果存成parquet或pickle避免重复解析JSON。df.to_parquet(clean_data.parquet)下次就pd.read_parquet(clean_data.parquet)直接加载速度能提升近一个数量级。5. 拓展玩法分析还能往上走多深基础的分析链路跑通后这个项目的进阶空间其实很深。我把自己试过的几个方向梳理一下你可以从中挑选感兴趣的去扩展。5.1 曲目特征分析为什么你会喜欢这些歌Spotify有个很强大的功能就是每首歌都有12个音频特征指标能量、舞蹈性、声学度、器乐度、语速、音量等全部可以通过API拿到。假如你把你Top 100歌曲的音频特征全部拉下来做一次聚类分析得到的簇大概率对应几种稳定的音乐场景健身房燃脂、深夜emo、通勤轻音乐。track_ids [item[id] for item in top_tracks] features sp.audio_features(track_ids)然后合成矩阵用KMeans聚类。由于这类API在线拉取有速率限制批量运行时最好加time.sleep(0.1)做限速。这个扩展项目能回答一个很有情绪价值的问题我的音乐品味到底是什么样的。5.2 歌词文本分析从歌词里读出你的情绪画像借助歌词平台的API下载自己所爱歌曲的歌词然后做分词、词频统计和情感分析形成一个最喜欢的100首歌里出现最多的关键词榜单。这类分析所用到的中文分词库是jieba情感倾向可以用SnowNLP来做粗粒度判断。虽然准确性不能跟商业级情感分析系统比但作为个人娱乐项目完全够用。做的时候有个坑很多歌词含有英文中英混合的分词要做过滤处理停用词表要自定义否则高频词全是you、the、的这类无意义的词。5.3 相互推荐用协同过滤的思路找另一个我如果你能拿到几个朋友的播放记录可以算一下歌手重叠度。社交关系题在数据分析里向来能引发猛烈讨论。挑两位朋友的歌手占比向量计算余弦相似度或Jaccard系数结果往往让人会心一笑你觉得品味差不多的人数据上可能差得很远。5.4 把分析工具化做一个每周自动报告更进一步可以用cron或计划任务每周固定时间运行脚本自动拉取最近一周的播放记录把统计结果渲染成HTML报告并邮件发送。这算是这个项目的终极形态——从一次性分析进化成持续在跑的数据服务。实现上只需要在脚本入口增加一个定时触发逻辑并做好日志输出即可。我自己跑了几周后发现每周报告最有价值的功能不是统计而是变化检测这周有没有突然冒出一个从来没有听过的歌手有没有连续三天播放同一张专辑这些都是值得回答的有趣问题。实操总结与经验收尾回头看我做这个项目的整个历程最深的体会就是数据本身不会讲故事但如果你足够了解自己数据会不断验证或推翻你的直觉。说句掏心窝的话请一定先跑通API快速那条链路再等导出文件不要让等待时间拖垮了你的兴趣。导出数据里的时间戳和艺术家名字其实已经足够完成文章里提到的所有统计音频特征再分析则是锦上添花可以后续再补。另外一个建议是保留原始下载的压缩包只读不解压程序里始终从原始文件解析。这样每次调整清洗逻辑时都能从一个稳定的初始状态开始避免因为重复处理导致数据污染。这个项目的好玩程度完全取决于你投入了多少曲目、经历了多少播放场景。如果手头有一份Spotify数据我建议立刻动手跑起来——分析结果里大概率有让你哎呀居然会这样的瞬间。那些瞬间才是数字真正有了温度的证据。
返回列表