1. 项目概述:用Python解锁你的Spotify音乐DNA
作为一名长期使用Spotify的音乐爱好者兼Python开发者,我最近发现了一个有趣的现象:虽然平台会定期生成年度听歌报告,但那些静态图表根本无法满足我对个人音乐偏好的深度挖掘需求。于是我用Python搭建了一套完整的分析系统,结果发现了许多连自己都惊讶的听歌模式——比如每周三下午三点总会不自觉地播放爵士乐,或者在雨天播放列表里90%都是独立民谣。
这个项目本质上是通过Spotify官方API获取你的完整听歌历史数据,然后用Python进行多维度的清洗、分析和可视化。不同于简单的播放次数统计,我们将关注:1)时间维度的听歌习惯分析 2)音乐特征的聚类研究 3)个性化推荐系统的雏形构建。整个过程只需要基础Python知识,但最终能产出堪比专业音乐分析平台的洞察报告。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与API配置
2.1 创建Spotify开发者应用
首先需要在Spotify开发者仪表板创建新应用:
- 点击"Create an App"按钮,填写应用名称和描述(如"My Listening Analyzer")
- 记录下自动生成的Client ID和Client Secret
- 在设置中添加回调地址(本地开发可用http://localhost:8888/callback)
重要提示:Client Secret相当于应用密码,绝对不能提交到Git等公开平台。建议使用python-dotenv管理这些敏感信息。
2.2 安装必要的Python库
推荐使用conda创建专属虚拟环境:
bash复制conda create -n spotify-analysis python=3.9
conda activate spotify-analysis
pip install spotipy pandas matplotlib seaborn scikit-learn python-dotenv
其中关键库的作用:
- spotipy:官方推荐的Spotify API Python封装库
- pandas:数据处理与分析的核心工具
- matplotlib/seaborn:可视化黄金组合
- scikit-learn:用于音乐特征的聚类分析
3. 数据获取与预处理
3.1 实现OAuth2.0认证流程
使用spotipy库简化认证流程的典型代码结构:
python复制import spotipy
from spotipy.oauth2 import SpotifyOAuth
scope = "user-library-read user-top-read user-read-recently-played"
sp = spotipy.Spotify(auth_manager=SpotifyOAuth(
scope=scope,
redirect_uri="http://localhost:8888/callback",
cache_path=".cache" # 保存token避免重复认证
))
3.2 获取核心听歌数据
我们可以通过多种API端点获取不同维度的数据:
python复制# 最近50条播放记录
recent_plays = sp.current_user_recently_played(limit=50)
# 长期音乐偏好(需注意时区问题)
top_tracks_short = sp.current_user_top_tracks(time_range='short_term', limit=50)
top_tracks_medium = sp.current_user_top_tracks(time_range='medium_term', limit=50)
top_tracks_long = sp.current_user_top_tracks(time_range='long_term', limit=50)
# 收藏的歌曲和专辑
saved_tracks = sp.current_user_saved_tracks(limit=50)
saved_albums = sp.current_user_saved_albums(limit=50)
3.3 数据清洗与增强
原始JSON数据需要转换为结构化DataFrame:
python复制import pandas as pd
def parse_track(track):
return {
"id": track["id"],
"name": track["name"],
"artist": ", ".join([a["name"] for a in track["artists"]]),
"duration_ms": track["duration_ms"],
"popularity": track["popularity"],
"added_at": track.get("added_at", ""),
"played_at": track.get("played_at", ""),
}
tracks_data = [parse_track(item["track"]) for item in saved_tracks["items"]]
df_tracks = pd.DataFrame(tracks_data)
更专业的做法是获取每首歌的音频特征(acousticness, danceability等):
python复制audio_features = sp.audio_features([track["id"] for track in tracks_data])
df_features = pd.DataFrame(audio_features).drop(columns=['type', 'uri', 'track_href', 'analysis_url'])
4. 多维数据分析实战
4.1 时间维度分析
首先转换时间戳并提取时间特征:
python复制df_tracks['played_at'] = pd.to_datetime(df_tracks['played_at'])
df_tracks['hour'] = df_tracks['played_at'].dt.hour
df_tracks['day_of_week'] = df_tracks['played_at'].dt.day_name()
df_tracks['month'] = df_tracks['played_at'].dt.month_name()
然后可以生成听歌时间热力图:
python复制import seaborn as sns
import matplotlib.pyplot as plt
plt.figure(figsize=(12, 6))
heatmap_data = df_tracks.groupby(['day_of_week', 'hour']).size().unstack()
sns.heatmap(heatmap_data, cmap="YlGnBu")
plt.title("Listening Patterns by Day and Hour")
plt.show()
4.2 音乐特征聚类
使用t-SNE算法对歌曲进行降维可视化:
python复制from sklearn.manifold import TSNE
features_to_use = ['danceability', 'energy', 'loudness', 'speechiness',
'acousticness', 'instrumentalness', 'liveness', 'valence']
X = df_features[features_to_use]
tsne = TSNE(n_components=2, random_state=42)
X_tsne = tsne.fit_transform(X)
plt.figure(figsize=(10, 8))
sns.scatterplot(x=X_tsne[:, 0], y=X_tsne[:, 1], hue=df_tracks['artist'])
plt.title("t-SNE Visualization of Music Taste")
plt.show()
4.3 情绪波动分析
利用valence(愉悦度)和energy(能量)指标:
python复制df_tracks['mood'] = pd.cut(
df_features['valence'],
bins=[0, 0.3, 0.7, 1],
labels=['Sad/Depressing', 'Neutral/Calm', 'Happy/Energetic']
)
plt.figure(figsize=(10, 6))
sns.countplot(data=df_tracks, x='hour', hue='mood')
plt.title("Mood Distribution by Hour of Day")
plt.show()
5. 高级分析与个性化推荐
5.1 构建简易推荐引擎
基于内容相似度的推荐算法:
python复制from sklearn.metrics.pairwise import cosine_similarity
def get_recommendations(track_id, df_features, df_tracks, top_n=5):
track_idx = df_tracks[df_tracks['id'] == track_id].index[0]
sim_matrix = cosine_similarity(df_features)
similar_indices = sim_matrix[track_idx].argsort()[-top_n-1:-1][::-1]
return df_tracks.iloc[similar_indices]
5.2 播放列表智能生成
自动创建基于当前心情的播放列表:
python复制def create_mood_playlist(sp, mood, limit=20):
# 根据情绪标签筛选歌曲
mood_tracks = df_tracks[df_tracks['mood'] == mood].sample(limit)
# 创建新播放列表
user_id = sp.me()['id']
playlist = sp.user_playlist_create(
user_id,
f"{mood} Mix - {pd.Timestamp.now().strftime('%Y-%m-%d')}",
public=False
)
# 添加歌曲
sp.playlist_add_items(playlist['id'], mood_tracks['id'].tolist())
return playlist
6. 实战技巧与避坑指南
6.1 API调用优化
-
速率限制:Spotify API限制为每秒10-20次请求,建议添加延时:
python复制import time time.sleep(0.1) # 控制请求频率 -
分页处理:当数据超过50条时需要处理分页:
python复制def get_all_saved_tracks(sp): results = sp.current_user_saved_tracks(limit=50) tracks = results['items'] while results['next']: results = sp.next(results) tracks.extend(results['items']) return tracks
6.2 数据持久化策略
建议将API返回的原始数据保存为JSON文件:
python复制import json
with open('spotify_data/raw_tracks.json', 'w') as f:
json.dump(saved_tracks, f, indent=2)
然后构建数据更新机制:
python复制def update_data(sp):
# 检查最后更新时间
if not os.path.exists('last_update.txt'):
last_update = '1970-01-01'
else:
with open('last_update.txt') as f:
last_update = f.read()
# 只获取新数据
new_tracks = []
results = sp.current_user_recently_played(after=last_update)
...
# 更新最后记录时间
with open('last_update.txt', 'w') as f:
f.write(pd.Timestamp.now().isoformat())
6.3 可视化优化技巧
-
使用Plotly实现交互式图表:
python复制import plotly.express as px fig = px.scatter(df_tracks, x='danceability', y='energy', color='mood', hover_data=['name', 'artist']) fig.show() -
创建雷达图展示音乐特征:
python复制def plot_radar_chart(track_id): features = df_features[df_features['id'] == track_id].iloc[0] categories = features_to_use values = features[categories].tolist() fig = go.Figure() fig.add_trace(go.Scatterpolar( r=values + values[:1], # 闭合图形 theta=categories + categories[:1], fill='toself' )) fig.update_layout(polar=dict(radialaxis=dict(visible=True))) fig.show()
7. 项目扩展方向
7.1 与Last.fm数据整合
如果你同时使用Last.fm,可以结合其API获取更长期的历史数据:
python复制import pylast
lastfm = pylast.LastFMNetwork(
api_key="YOUR_API_KEY",
api_secret="YOUR_API_SECRET",
username="YOUR_USERNAME",
password_hash=pylast.md5("YOUR_PASSWORD")
)
lastfm_tracks = lastfm.get_user("username").get_recent_tracks(limit=500)
7.2 部署为自动化仪表盘
使用Streamlit快速构建Web应用:
python复制import streamlit as st
st.title("My Spotify Analytics")
time_range = st.selectbox("Select Time Range", ["short_term", "medium_term", "long_term"])
if st.button("Analyze"):
top_tracks = sp.current_user_top_tracks(time_range=time_range)
df = pd.DataFrame([parse_track(track) for track in top_tracks['items']])
st.bar_chart(df['artist'].value_counts().head(10))
7.3 音乐记忆时间胶囊
创建一个年度音乐记忆功能:
python复制def create_time_capsule(year):
# 获取特定年份的播放记录
yearly_tracks = get_tracks_from_db(year) # 需要事先建立本地数据库
# 生成年度报告
report = f"""
# Your {year} in Music
- Total Tracks Played: {len(yearly_tracks)}
- Top Artist: {yearly_tracks['artist'].mode()[0]}
- Most Played Song: {yearly_tracks['name'].mode()[0]}
- Mood Distribution: {yearly_tracks['mood'].value_counts().to_dict()}
"""
# 创建播放列表
playlist = create_playlist_from_tracks(yearly_tracks)
return report, playlist
