1. 项目概述:用Python解锁你的Spotify音乐DNA
最近在整理电脑时发现,我的Spotify账号已经积累了7年的听歌记录。作为每天通勤必开音乐的人,突然很好奇自己这些年到底听了些什么。官方提供的年度回顾虽然精美,但数据维度有限。于是决定用Python写个脚本,把那些沉睡在Spotify服务器上的原始数据真正"榨"出汁来。
这个项目适合所有想了解自己音乐品味的数据爱好者。不需要专业编程基础,只要会安装Python库就能跟着操作。最终我们能获得比官方报告更细致的分析,比如:
- 每周听歌时段分布热力图
- 常听歌曲的BPM(每分钟节拍数)变化曲线
- 不同季节的流派偏好迁移
- 歌手收听时长排行榜(可能会发现一些自己都没意识到的"隐形最爱")
提示:Spotify官方API限制每小时最多300次请求,建议选择3个月以上的数据时需要分时段获取
2. 环境准备与API对接
2.1 开发环境配置
推荐使用VSCode + Jupyter Notebook组合,方便实时查看数据分析结果。需要安装的核心库包括:
pip install spotipy pandas matplotlib seaborn其中spotipy是Spotify官方API的Python封装库。如果遇到证书错误,可以尝试:
pip install --upgrade certifi2.2 获取API凭证
- 登录 Spotify开发者仪表盘
- 创建新应用(类型选"个人研究用途")
- 记录下Client ID和Client Secret
- 在设置中添加回调地址:
http://localhost:8888/callback
建议将凭证保存在环境变量中:
import os os.environ['SPOTIPY_CLIENT_ID'] = '你的ClientID' os.environ['SPOTIPY_CLIENT_SECRET'] = '你的ClientSecret' os.environ['SPOTIPY_REDIRECT_URI'] = 'http://localhost:8888/callback'2.3 认证流程实现
使用OAuth2授权码流程获取token:
import spotipy from spotipy.oauth2 import SpotifyOAuth scope = "user-library-read user-read-recently-played user-top-read" sp = spotipy.Spotify(auth_manager=SpotifyOAuth(scope=scope))首次运行会弹出浏览器窗口要求登录授权。成功后token会自动缓存到本地,后续调用无需重复认证。
3. 数据采集与清洗
3.1 获取近期播放记录
recent_tracks = sp.current_user_recently_played(limit=50)这个端点最多返回最近50条播放记录。如果需要更早的数据,需要通过分页参数循环获取:
def get_all_recent_tracks(days=30): results = [] before = int(time.time()) * 1000 while True: batch = sp.current_user_recently_played(limit=50, before=before) if not batch['items']: break oldest_time = batch['items'][-1]['played_at'] before = int(pd.to_datetime(oldest_time).timestamp() * 1000) results.extend(batch['items']) if (pd.to_datetime('now') - pd.to_datetime(oldest_time)).days > days: break return results3.2 获取曲目音频特征
Spotify为每首歌提供了13种专业音频特征:
track_ids = [item['track']['id'] for item in recent_tracks] audio_features = sp.audio_features(track_ids)关键特征包括:
- danceability(舞蹈性)
- energy(能量感)
- valence(情绪积极度)
- tempo(BPM)
- speechiness(口语化程度)
3.3 数据标准化处理
将原始JSON转换为结构化DataFrame:
import pandas as pd def flatten_track(track): return { 'played_at': track['played_at'], 'name': track['track']['name'], 'artist': ', '.join([a['name'] for a in track['track']['artists']]), 'duration_ms': track['track']['duration_ms'], **track['track']['audio_features'] } df = pd.DataFrame([flatten_track(t) for t in recent_tracks])处理时间字段:
df['played_at'] = pd.to_datetime(df['played_at']) df['hour'] = df['played_at'].dt.hour df['day_of_week'] = df['played_at'].dt.dayofweek4. 可视化分析与洞察挖掘
4.1 听歌时段热力图
import seaborn as sns import matplotlib.pyplot as plt plt.figure(figsize=(12,6)) heatmap_data = df.groupby(['day_of_week','hour']).size().unstack() sns.heatmap(heatmap_data, cmap='YlOrRd') plt.title('Weekly Listening Pattern') plt.xlabel('Hour of Day') plt.ylabel('Day of Week') plt.show()我的结果显示周三下午3-4点有个明显的收听高峰,对应每周最困的工作时段。
4.2 情绪能量矩阵
plt.figure(figsize=(10,8)) sns.scatterplot(data=df, x='valence', y='energy', hue='artist', size='duration_ms', sizes=(50,200), alpha=0.7) plt.title('Energy vs Valence by Artist') plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')这个图能直观显示你常听歌曲的情绪分布。我发现自己工作时常听高能量低情绪值的电子乐,而周末则偏好中能量高情绪值的独立摇滚。
4.3 历史品味演变
用滚动窗口分析音乐特征的变化:
df.set_index('played_at', inplace=True) weekly_features = df[['danceability','energy','valence']].resample('W').mean() plt.figure(figsize=(12,6)) for col in weekly_features.columns: sns.lineplot(data=weekly_features[col], label=col) plt.title('Weekly Audio Feature Trends') plt.ylabel('Value')我的数据显示每年冬季valence值明显下降,可能和季节性情绪波动有关。
5. 高级分析与自动化
5.1 创建个人音乐指纹
用KMeans聚类识别你的音乐偏好模式:
from sklearn.cluster import KMeans features = df[['danceability','energy','valence','tempo']] kmeans = KMeans(n_clusters=3).fit(features) df['cluster'] = kmeans.labels_ plt.figure(figsize=(10,6)) sns.scatterplot(data=df, x='valence', y='energy', hue='cluster', palette='viridis')我的结果分出三类:高能量工作音乐、中等能量休闲音乐、低能量助眠音乐。
5.2 自动化周报生成
用Jinja2模板自动生成HTML报告:
from jinja2 import Template template = Template(''' <h1>Your Weekly Music Report</h1> <p>Top Artists: {{ top_artists|join(", ") }}</p> <!-- 更多模板内容 --> ''') report = template.render( top_artists=df['artist'].value_counts().head(3).index.tolist() )配合Windows任务计划或cronjob可以实现每周自动生成报告并邮件发送。
6. 性能优化与注意事项
- 请求限流处理:
from time import sleep from tenacity import retry, stop_after_attempt, wait_exponential @retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1)) def safe_api_call(func, *args): try: return func(*args) except Exception as e: if "429" in str(e): sleep(int(e.headers.get('Retry-After', 10))) raise- 数据缓存策略:
import json from pathlib import Path CACHE_DIR = Path('spotify_cache') def get_with_cache(endpoint, params): cache_file = CACHE_DIR / f"{endpoint}_{hash(frozenset(params.items()))}.json" if cache_file.exists(): return json.loads(cache_file.read_text()) data = safe_api_call(getattr(sp, endpoint), **params) cache_file.write_text(json.dumps(data)) return data- 内存优化技巧:
- 对于大型数据集,使用
dask替代pandas - 将datetime转换为unix时间戳存储
- 对artist等字符串字段使用category类型
我在处理3年数据时(约2万条记录),原始JSON文件有180MB,经过优化后内存占用降至28MB。