年底各大平台都会给你端出年度报告,卡片做得一年比一年精致,可数字背后到底是怎么算出来的,平台基本不会告诉你,也不会把原始数据交给你。作为一个把耳机当器官的人,我对Spotify这些年攒下的听歌数据一直充满好奇:深夜单曲循环的到底是哪几首?过去一年里哪个艺人占据了我的耳朵排行榜第一名?听歌时段分布和心情波动有没有规律?带着这一堆疑问,我干脆用Python写了一套自己的分析脚本,把Spotify听歌数据完整拉出来、清洗、统计、可视化,顺便把从Python安装、申请API到出图的整条链路都摸了一遍。这篇文章就把这套流程完整拆开:不光是教你怎么调接口,还会把每一行代码背后的设计逻辑讲清楚,适合两类人——想看看平台年度报告之外真实数据的Spotify重度用户,和正缺一个有真实业务场景练手的Python数据分析初学者。
1. 项目思路与整体设计:你想从听歌数据里看到什么
1.1 平台年度报告之外,API能给你什么
Spotify自己的年度总结做得越来越好,但它的本质是平台用自家算法挑选出来的“宣传页”,而不是一份可供你自由分析的原始报表。比如年度报告中会告诉你“你今年听了300小时音乐”,却不会告诉你这300小时分布在哪一天、哪个时段、哪一首歌被你循环了多少遍。如果你只想看结论,平台报告完全够用;但如果你想回答“我到底在什么情绪下听什么歌”“我的音乐品味是不是真的偏向某个风格”,就必须回到数据源头。
Spotify Web API恰好提供了这个入口。通过API,你能拿到播放时间戳、曲目与艺人信息、流派标签,以及一组被叫做“音频特征”的量化字段。把这些数据拉下来之后,你可以去回答的平台报告里根本不会出现的问题:
- 一周七天里,我哪天听歌最多?每天哪个小时是耳机最忙的时间?
- 我的播放列表里是否有重复率极高的“耳朵单曲循环区”?
- 按播放次数排序和按累计时长排序,结果差异有多大?
- 我喜欢的歌在danceability、energy、valence这些音频特征上是平均值还是偏科?
这些问题的答案,组合起来就是你个人的“音乐肖像”。我第一次跑完脚本时,最大感受是:平台觉得我是某某流派的乐迷,但从数据看,我的情绪波动远比一个标签复杂。这是API比年度报告更有价值的地方——它不替你讲故事,只把原材料摆在你面前。
1.2 整体技术链:从HTTP请求到图表只需四个工具
这个项目并不需要搭一个什么庞大的数据处理平台,相反,我把技术栈刻意控制在一套很轻的组合里:Python作为主语言,spotipy负责封装Spotify API的授权与请求,pandas负责清洗和聚合,matplotlib负责画图。如果中途想调试分段数据,也可以顺手装一个Jupyter Notebook跑交互代码,但完全不是必需项。
为什么选这套组合?因为“用Python分析听歌数据”这个项目的核心目标不是炫技,而是让我能清楚看到从“拉取数据”到“生成图表”的每一个环节。spotipy比直接用requests调接口简单得多,它内部把OAuth授权、请求头、参数拼接和异常处理都做掉了,省去大量重复代码;pandas是表格数据处理的标准工具,groupby、pivot_table这类操作几行就能完成;matplotlib虽然画出的图不是最花哨的,但胜在可控性强、依赖少,适合做个人分析项目。
如果你是非技术背景、刚开始接触Python,我也建议用这套组合。图省事可以去找现成的听歌统计网站,但自己走一遍流程之后,你对“数据是怎么变成结论”的理解是完全不一样的。整条链路跑通一次,你等于同时实践了API调用、数据清洗、聚合统计、可视化四件事,这比单纯刷语法题有用得多。
2. 环境准备与Spotify API接入:从Python安装到OAuth授权一次跑通
2.1 先搭开发环境:Python版本与虚拟环境选择
项目的第一个实际门槛是Python安装。目前这个分析脚本对Python版本要求不苛刻,3.9到3.12之间都能跑,我建议直接装当前较新的3.11或3.12版本。在官网下载安装包时,有一个细节很多人会忽略:安装向导第一步务必勾选“Add Python to PATH”,否则后面在命令行敲python会提示找不到命令,还得回头手动改系统环境变量,非常折腾。
Python装好之后,我强烈建议为这个项目单独建一个虚拟环境,而不是直接往全局环境里塞包。虚拟环境相当于给项目隔出了一个独立的小房间,里面装的库版本不会和其他项目互相干扰。命令行里执行:
python -m venv .venv # macOS / Linux 激活方式 source .venv/bin/activate # Windows 激活方式 .venv\Scripts\activate激活后,命令行提示符前面会出现(.venv)字样,这就代表你已经进入虚拟环境了。接着安装项目依赖:
pip install spotipy pandas matplotlib seabornspotipy是Spotify的Python SDK,pandas负责数据处理,matplotlib和seaborn负责可视化。如果你打算用Jupyter Notebook边写边调,可以再执行一句pip install jupyter。
这里顺便说一句,有些同学的电脑里可能已经装过Anaconda,那环境问题就更好解决,直接用conda创建新环境即可,思路完全一致。这个项目不是大型工程,环境准备阶段控制在十分钟以内比较合理,如果卡在这一步太久,后面容易泄气。
2.2 在Spotify开发者平台创建应用,拿到两个关键凭证
要用Spotify API,前提是在开发者平台创建一个应用。整个流程不复杂,大致是:登录Spotify账号,进入开发者平台,点击Create App,填写应用名称和描述,在Redirect URI一栏填上http://localhost:8888/callback,然后创建。
创建完成后,进入应用详情页,你会看到一串Client ID,以及一个默认隐藏、需要点击“Show client secret”才会展开的Client Secret。这两个字符串就是后面访问API的钥匙。Client ID相当于你的应用标识,Client Secret相当于密码,它们会通过OAuth授权流程用来换取访问令牌。
有个容易踩坑的地方是Redirect URI。Spotify只允许回调地址与你登记在开发者平台上的地址一致,如果两边差一个符号,授权时就会报错。我统一用http://localhost:8888/callback,是因为本地回调比较灵活,不需要一个真实部署的服务器地址。理解这一点后,你后面看到OAuth报错时也就知道往哪个方向排查了。
这两个凭证最好不要直接硬编码在脚本里。常见做法是通过环境变量读取,避免脚本被分享出去时把秘密一起泄露。比如在命令行里先设置SPOTIFY_CLIENT_ID和SPOTIFY_CLIENT_SECRET两个变量,然后在Python代码里用os.getenv读取。
2.3 用spotipy完成授权:OAuth流程背后发生了什么
Spotify API使用的是OAuth授权流程,对新手来说第一次遇到可能会觉得绕,但把它拆开其实很简单。你可以把一个桌面应用想象成一个餐厅服务员,他不能直接拿你的银行卡密码去结账,必须先经过你本人的授权,餐厅才能从你账户里扣钱。OAuth就是这套授权机制:你的Spotify账号相当于银行,Python脚本相当于餐厅,回调地址相当于结账时服务员递过来的小票。
spotipy把大部分细节都封装好了。我习惯用手动粘贴回调URL的模式,因为这种模式对你理解整个流程最有帮助,而且不依赖本机额外开启端口。代码如下:
import os import spotipy from spotipy.oauth2 import SpotifyOAuth scope = "user-top-read user-read-recently-played" sp_oauth = SpotifyOAuth( client_id=os.getenv("SPOTIFY_CLIENT_ID"), client_secret=os.getenv("SPOTIFY_CLIENT_SECRET"), redirect_uri="http://localhost:8888/callback", scope=scope, cache_path=".spotify_token", ) auth_url = sp_oauth.get_authorize_url() print("请打开下面网址,完成授权:", auth_url) callback_url = input("授权完成后,粘贴浏览器地址栏里的完整URL:") code = sp_oauth.parse_response_code(callback_url) token_info = sp_oauth.get_access_token(code) sp = spotipy.Spotify(auth_manager=sp_oauth) print("授权成功,当前用户:", sp.me()["display_name"])这里scope参数很重要,它决定了脚本能读取你哪些数据。我通常只申请user-top-read和user-read-recently-played,因为这两个权限足够拿到热门曲目、热门艺人和最近播放记录。如果需要读取收藏,再额外加一个user-library-read。原则是权限能少则少,自己的数据也不要在授权页面上大放送。
第一次运行脚本时,浏览器会打开Spotify授权页面,点击同意后地址栏会跳转到一个长URL,把那串完整URL复制回来粘贴进终端即可。spotipy拿到授权码后会自动换出access token和refresh token,并且通过cache_path参数把token信息缓存到本地文件.spotify_token里。这样第二次运行时你不需要重新授权,脚本会自动读取缓存,只有当token真正过期时才会提示重新走一遍流程。
3. 数据抓取与清洗:把API返回变成可以分析的表格
3.1 抓取顶部曲目、艺人、最近播放记录
授权成功后,就可以开始抓数据了。Spotify API里的常用接口有三个:当前用户的热门艺人(current_user_top_artists)、热门曲目(current_user_top_tracks)、最近播放记录(current_user_recently_played)。前两个接口支持一个有意思的时间范围参数time_range,可选short_term、medium_term、long_term,分别对应近一个月、近半年、长期以来的收听习惯。
我用一个函数封装最近播放记录的获取逻辑,直接把结果转换成pandas的DataFrame:
import pandas as pd def get_recent_tracks(sp, limit=50): results = sp.current_user_recently_played(limit=limit) records = [] for item in results["items"]: track = item["track"] records.append({ "song": track["name"], "artist": track["artists"][0]["name"], "album": track["album"]["name"], "song_id": track["id"], "played_at": item["played_at"], "duration_ms": track["duration_ms"], }) return pd.DataFrame(records) recent_df = get_recent_tracks(sp, limit=50) print(recent_df.head())如果感觉50条不够,可以在函数外部循环翻页,把多页数据合并起来。翻页机制在后面的分析里同样会用到,我一般写成循环加sleep的结构,避免一口气请求太多接口触发限流。
获取热门艺人和热门曲目的代码也类似:
top_artists = sp.current_user_top_artists(limit=50, time_range="long_term") top_tracks = sp.current_user_top_tracks(limit=50, time_range="long_term") for idx, artist in enumerate(top_artists["items"]): print(idx + 1, artist["name"], artist["genres"])第一次拉数据的时候你会发现,返回值是一个嵌套很深的JSON结构,曲目的artists字段还包含了一个列表。这里有个新手很容易犯的错:我一开始只取track["artists"][0]["name"],遇到合作曲目时就会丢失第二、第三个艺人信息。后来我改成把所有艺人名用逗号拼起来,分析结果才准确。
3.2 音频特征是什么:danceability、energy、valence等关键词
播放记录只能告诉你“听了什么、什么时候听的”,却不能直接告诉你“你为什么会喜欢这类歌”。要回答后者,就得靠音频特征字段。Spotify给每首歌都标了一组0到1之间的数值,你可以把它理解成平台算法对歌曲气质做的量化描述。我常用的几个指标是:
danceability表示歌曲适合跟着律动的程度,数值越高节奏感越强,适合跳舞;energy是活跃度,越高越让人觉得充满爆发力;valence是情绪积极性,高valence的歌听起来明亮、快乐,低valence的歌往往带着悲伤或压抑的情绪;acousticness是原声程度,越高代表越偏向木吉他、钢琴之类的原声录音;strumentalness表示无人声的比例,越高说明越偏纯音乐;speechiness则表示歌词像说话而非唱的比例,说唱和脱口秀类内容的数值会偏高。
你可以把这些字段当成人格测试的维度。有人听歌偏好高能量低valence,可能说明日常更依赖音乐来释放压力;有人acousticness常年偏高,可能更享受安静的场景音乐。我第一次看到自己的平均数值时,发现自己听歌的valence常年偏低,但energy不低,这才意识到自己总在情绪复杂时选择那些有劲儿却略带拧巴的歌。
获取这些字段很简单,拿到曲目ID列表后,调用audio_features接口即可:
ids = [track["song_id"] for track in top_tracks["items"][:50]] features = sp.audio_features(ids) for song, f in zip([t["name"] for t in top_tracks["items"][:50]], features): if f: print(song, f["danceability"], f["energy"], f["valence"])需要注意接口一次最多传50个ID,所以我用切片取前50个。如果歌单长度超过50,需要分批调用后再合并。
3.3 清洗和结构化:从嵌套JSON到干净的DataFrame
API返回的数据并不直接适合分析,缺值、重复、乱序都是常态。我拿到数据后,会先做三件事:时间标准化、去重、补充衍生字段。
第一步,把played_at字符串转成pandas的时间类型,然后从中拆出小时、星期几这些分析维度。有一个坑必须提醒:Spotify返回的时间戳是UTC时区的,不是你的本地时间。如果你的使用场景在非UTC时区,直接按dt.hour统计会得到完全不一样的结果。我通常先tz_convert到自己所在时区,再提取小时字段。
recent_df["played_at"] = pd.to_datetime(recent_df["played_at"]) recent_df["played_at"] = recent_df["played_at"].dt.tz_convert("Asia/Shanghai") recent_df["hour"] = recent_df["played_at"].dt.hour recent_df["weekday"] = recent_df["played_at"].dt.dayofweek第二步,去重。最近播放记录里可能出现同一首歌在几秒内被重复记录,或同一分钟出现两条相同记录的情况,所以我会用drop_duplicates去掉完全相同的行。如果你的目标是统计播放次数而不是播放事件数,这一步要格外注意,因为按artist聚合时重复数据会直接影响排名。
第三步,把音频特征字段加入主DataFrame。我一般用曲目ID作为关联键,把audio_features返回的结果merge进来。最终形成的表大致长这样:每一行是一次播放事件,包含歌名、艺人、播放时间、时长,以及这首歌的danceability、energy、valence等音频特征。这个表就是后续所有分析的地基。
4. 核心分析:从不同维度拆解你的听歌习惯
4.1 按小时拆解:你的耳机在一天里哪个时段最忙
拿到干净的DataFrame后,第一件让我觉得有意思的分析是按播放时间分组。把“小时”作为分组字段,统计每个小时内的播放次数,能很清楚看到自己的收听节奏。
hourly = recent_df.groupby("hour")["song"].count().reset_index() hourly.columns = ["hour", "play_count"] top_hour = hourly.sort_values("play_count", ascending=False).head(5) print(top_hour)我自己的分析结果显示,晚上22点到23点是我播放量最高的时段,工作日早上9点到10点还有一个明显的小高峰。对照一下自己的生活规律,其实完全对得上:上午一般戴着耳机写文档,晚上则是放松时间,音乐当背景音。数据最大的魅力就在这里,它不是告诉我“你爱听什么”,而是告诉我“你在什么状态下更依赖音乐”。
如果你想看得更细,可以进一步把工作日和周末分开,分别统计每小时播放量。做法是在groupby之前先增加一列is_weekend,然后按is_weekend和hour两个字段一起分组。这样能对比出通勤日的音乐选择和休息日有什么区别,分析维度一下就丰富起来了。
4.2 Top N分析:用播放次数和总时长双维度排座次
听歌排行是所有人都想看的榜单,但这里有一个容易忽略的细节:按歌曲出现次数排名和按艺人出现次数排名,得到的结果并不一样。我习惯把两套榜单一起算,因为它们回答的问题完全不同。
次数榜单计算的是“谁出现的频率最高”:
artist_play_count = recent_df.groupby("artist")["song"].count().sort_values(ascending=False).head(10)时长榜单计算的是“谁占据了我耳朵的时间最多”:
artist_duration = recent_df.groupby("artist")["duration_ms"].sum() / 60000 top_duration = artist_duration.sort_values(ascending=False).head(10)对比这两份榜单,你会发现一些有趣的错位。比如某个歌手的歌平均只有两分钟,但因为无限循环所以次数排名第一;另一个歌手单曲动辄七八分钟,播放次数没那么高,累计时长却悄无声息地爬到了前面。这种错位恰恰能反映你的收听习惯:你是在找“短平快的刺激”,还是愿意花一整张专辑的时间沉浸在长叙事里。
同样的逻辑也适用于歌曲本身。你可以统计单曲播放次数和单曲累计播放时长两个指标,再分别取Top 10。如果一份榜单和另一份榜单有半壁江山重合,说明你的听歌习惯相当稳定;如果差异很大,说明你既有高频切换的一面,也有长期沉浸的一面。
4.3 音乐人格画像:用均值看看你的口味偏好
把音频特征汇总成平均值,可以得到一张抽象的“口味偏好画像”。我用下面这段代码把几个关键特征的平均值拉出来:
feature_cols = ["danceability", "energy", "valence", "acousticness", "instrumentalness", "speechiness"] feature_means = recent_df[feature_cols].mean().round(3) print(feature_means)光看绝对值可能不好理解,更好的做法是做对比。一种对比方法是用平台平均数据或好友的数据做参照,另一种是把自己最近一个月的均值(short_term)和长期均值(long_term)放在一起比较,看看音乐口味是否正在漂移。我就发现自己的short_term energy长期高于long_term,说明最近几个月我听的歌越来越“吵”,很可能是写稿压力变大了。
如果你喜欢更直观的方式,可以把自己的均值落在0到1的坐标轴上,直接看哪个维度特别突出。拿我自己举例,instrumentalness和acousticness一直偏低,说明我的听歌口味整体偏向人声和录音室作品,而speechiness适中,说明纯说唱和纯音乐都不是我的主力区。这个结果和我在音乐平台上的标签基本吻合,但多了一层量化解释,顿时觉得自己懂点数据就是不一样。
5. 可视化结果:把表格里单调的数字变成音乐画像
5.1 用条形图呈现年度Top歌手
分析做到这里,数据已经足够丰富了,但一堆数字还是不如一张图直观。我做的第一个可视化是横向条形图,用来展示Top 10艺人的播放次数。
import matplotlib.pyplot as plt plt.rcParams["font.sans-serif"] = ["SimHei"] # 如果系统没有SimHei,换你电脑里的中文字体名 plt.rcParams["axes.unicode_minus"] = False top10 = artist_play_count.head(10).sort_values() font_size = 10 top10.plot(kind="barh", figsize=(8, 6), color="#1DB954") plt.title("播放次数 Top 10 艺人") plt.xlabel("播放次数") plt.tight_layout() plt.show()画图时最容易翻车的是中文显示。Windows下我用SimHei一般没问题,macOS可以改成PingFang SC或者Arial Unicode MS,Linux则可能需要安装额外的中文字体。如果第一次出图时中文全部变成方块,别慌,先检查当前系统有哪些中文字体,然后把plt.rcParams["font.sans-serif"]换成对应字体名就行。还有一个小细节:负号是ASCII字符,不设置axes.unicode_minus为False的话,横轴上的负数可能变成乱码。
5.2 用热力图看清一周听歌规律
如果说柱状图适合看排名,那么热力图更适合看二维规律。想知道“一周七天、每天24小时,我的播放热度是怎么分布的”,用pivot_table加imshow就能画出来。
pivot = recent_df.pivot_table( index="weekday", columns="hour", values="song", aggfunc="count" ).fillna(0) fig, ax = plt.subplots(figsize=(12, 5)) im = ax.imshow(pivot, cmap="viridis", aspect="auto") ax.set_xticks(range(24)) ax.set_yticks(range(7)) ax.set_yticklabels(["周一", "周二", "周三", "周四", "周五", "周六", "周日"]) plt.colorbar(im) plt.title("一周播放热度(按小时)") plt.show()这张图的信息密度非常高。一眼看过去,哪个色块最深,就是你一周里最依赖耳机的时间段。我自己的热力图在周五深夜和周六上午各有一块亮斑,这解释了一件事:我周末起得并不早,但醒来的第一反应很可能是放歌当背景音。热力图的可贵之处在于它不会美化你的行为,它只诚实地记录你在什么时候反复打开播放器。
5.3 用雷达图画一张“音乐人格”
最后一个可视化是雷达图,把前面算好的几个音频特征均值画成多边形的形状。做法是让每个坐标轴代表一个特征,多边形的“胖瘦”直接反映你的口味倾向。
import numpy as np labels = ["danceability", "energy", "valence", "acousticness", "instrumentalness", "speechiness"] values = [recent_df[label].mean() for label in labels] values += values[:1] angles = np.linspace(0, 2 * np.pi, len(labels), endpoint=False).tolist() angles += angles[:1] fig, ax = plt.subplots(figsize=(6, 6), subplot_kw={"projection": "polar"}) ax.plot(angles, values, marker="o", linewidth=2) ax.fill(angles, values, alpha=0.25) ax.set_xticks(angles[:-1]) ax.set_xticklabels(labels) plt.title("我的音乐人格画像") plt.show()雷达图第一次画出来的时候,我盯着看了一会儿,感觉像是拿到了一份关于自己耳朵的体检报告。energy和danceability拉出去一大块,acousticness缩在角落里,感觉和我平时偏好的电子、摇滚风格是对得上的。如果你觉得自己的雷达图太扁,基本说明你的口味过于集中在某几个类型,后续反而可以单独拉出那些分布外的歌曲看看,没准能找到一些被你忽略的宝藏。
可视化环节的通用经验是:不要一口气画五张图堆一起看,而是每张图只回答“一个问题”。条形图回答“谁最多”,热力图回答“什么时候听”,雷达图回答“口味长什么样”。图少一点,思考的时间反而多一点,这个原则在个人数据分析项目里特别受用。
6. 常见问题与避坑指南:我踩过的坑全在这
6.1 按错误信息分类:从OAuth到HttpError
整个项目最让人头秃的部分大概率集中在授权和请求阶段。我把遇到过的问题整理成一张表,方便你报错时直接对照:
| 问题现象 | 常见原因 | 解决办法 |
|---|---|---|
| 授权页跳转后报“invalid_client” | Client Secret填错或没有设置环境变量 | 检查开发者平台的应用设置是否和你代码里的环境变量一致 |
| 授权成功后第二次运行又要求重新授权 | cache_path没设置,或缓存文件权限有问题 | 增加cache_path参数;确认缓存文件未被删除 |
| 调用接口报403 | 当前scope权限不足,或token失效 | 检查scope是否包含对应接口权限;删除旧缓存重新授权 |
| 调用接口报404 | 曲目ID或艺人ID有误,或API地址拼错 | 打印请求链接和参数,确认ID确实存在 |
| 中文标签在图中变成方块 | 系统缺少对应中文字体 | 改用系统中已安装的中文字体名并设置rcParams |
| 返回的数据量明显偏少 | API单次返回有上限,且未做分页处理 | 循环翻页,把多页结果合并 |
| played_at时间与本地时间不一致 | API返回的是UTC时间 | 用tz_convert转到本地时区再提取小时字段 |
我特别强调一下scope权限问题。Spotify API的错误提示不算友好,403错误并不总会在文案里写清楚到底是权限不足还是token过期。排查时先检查是不是权限问题,再检查缓存token,最后才去怀疑代码逻辑。这个排查顺序能省下很多时间。
6.2 配额、Token过期与数据分页
Spotify API对普通应用有请求频率限制,虽然个人项目的量级通常很难触发,但一旦写了一个循环去抓几千条历史记录,就可能在某个瞬间收到429状态码。429的意思是请求太频繁,服务器让你慢一点。解决方式很朴素:在循环里加time.sleep(0.5),让每次请求之间间隔半秒,实在不行就加退避逻辑,遇到429后指数退避再重试。
分页是另一个必然遇到的坑。current_user_top_artists和current_user_recently_played单次请求最多返回50条,超出部分需要通过offset参数偏移。写一个循环翻页并不会让代码复杂很多,但会让数据量从50变成500,分析结果自然也稳定得多。
Token过期问题也不少见。spotipy正常情况下会用refresh token自动续期,但如果你把cache文件删了或者换了一台电脑运行脚本,就需要重新授权。我的习惯是:把.spotify_token文件纳入项目目录但不提交到公开仓库,这样既避免重复授权,也避免了token泄露。
6.3 几个实用技巧:缓存Token、控制请求频率、别只取第一位艺人
关于缓存Token,这里有个小技巧值得多说一句。当你拿到access token后,spotipy会把token信息写到cache_path指定的文件里。第二次运行脚本时,它会优先尝试刷新而不是重新弹授权页面。这看起来是默认行为,但前提是你每次创建SpotifyOAuth时都传入同一个cache_path。如果你图省事不传,默认会生成.cache文件,乱用文件名的后果是每个缓存文件里的token源不一致,会频繁触发重新授权。
关于控制请求频率,我自己的脚本里会额外记录“上次请求时间”,如果两次请求间隔太短就自动sleep。直接一点的做法是写一个简单的装饰器或工具函数,统一包住所有API调用。这样既不痛不痒地把接口调用频率限制住了,后续想调整间隔也只要改一个地方。
还有一个容易被忽略的字段是track["artists"]。这是一个列表,因为歌曲可能是多人合作。如果只取[0],任何合唱曲目都会被记到第一位艺人名下,这会让Top艺人榜单产生误差。我之前就是这么干的,结果某支组合的分身歌手莫名被统计成了单飞歌手。后来统一改成“把所有艺人名用逗号连接”,并将“完整艺人组合”作为分组依据,统计结果才恢复正常。
最后再分享一个我自己习惯的做法:每次跑完分析,我会把最终生成的DataFrame保存成CSV文件放本地。这样做的好处是,后续想换一种角度重新分析时,不需要再发起API请求,直接用本地数据跑,既快又不消耗配额。你还可以在同一张CSV里叠加上月份的数据,累积足够时长后做成更长期的趋势分析。
我第一次跑完这套分析时,最意外的发现不是某个歌手的排名,而是自己一天内听歌时段的分布比想象中更规律。那之后我经常会把新拉下来的数据和旧数据做对比,观察自己的音乐口味是不是正在慢慢变化。如果你也对这类问题感兴趣,可以从最简单的一步开始:装好Python,创建完开发者应用,用脚本拉下最近50条播放记录,然后试着统计一下你最常听的5个歌手。做完这一步,你离一张属于自己的音乐人格雷达图,其实也就只剩两三个代码块的距离。