1. 项目概述:用Python解锁你的音乐DNA
作为一名长期使用Spotify的音乐爱好者兼Python开发者,我发现平台提供的年度回顾(Wrapped)功能虽然有趣,但远远不能满足深度分析需求。通过Python直接调用Spotify API,我们可以挖掘出更多隐藏的听歌行为模式——比如你在工作日和周末的听歌风格差异、随着季节变化的音乐偏好迁移,甚至是特定情绪状态下的选曲规律。
这个项目特别适合:
- 想用技术手段量化个人音乐品味的数据爱好者
- 需要音乐数据分析练手的Python初学者
- 计划创建个性化音乐推荐系统的开发者
- 单纯好奇自己听歌习惯的普通用户
提示:Spotify官方API对非商业用途非常友好,免费账户也能获取足够丰富的听歌历史数据
2. 环境准备与API配置
2.1 创建Spotify开发者应用
首先访问 Spotify开发者仪表板 ,用你的Spotify账号登录后:
- 点击"Create App"按钮
- 填写应用名称(如"My Listening Analysis")
- 在应用描述中注明"Personal use for music data analysis"
- 同意条款后点击"Create"
创建成功后记录两个关键信息:
- Client ID:相当于你的应用身份证
- Client Secret:用于验证的密钥
2.2 安装必要的Python库
推荐使用conda创建独立环境:
conda create -n spotify-analysis python=3.9 conda activate spotify-analysis pip install spotipy pandas matplotlib seaborn其中各库的作用:
spotipy:官方推荐的Spotify API Python客户端pandas:数据处理与分析核心工具matplotlib/seaborn:可视化黄金组合
2.3 配置认证流程
在项目目录创建config.json文件:
{ "SPOTIPY_CLIENT_ID": "你的Client ID", "SPOTIPY_CLIENT_SECRET": "你的Client Secret", "SPOTIPY_REDIRECT_URI": "http://localhost:8888/callback" }重要安全提示:永远不要将config.json上传到公开Git仓库!建议添加到.gitignore
3. 数据获取与清洗
3.1 实现OAuth认证流程
创建auth.py处理认证:
import spotipy from spotipy.oauth2 import SpotifyOAuth import json def get_spotify_client(): with open('config.json') as f: config = json.load(f) scope = "user-library-read user-top-read user-read-recently-played" return spotipy.Spotify(auth_manager=SpotifyOAuth( scope=scope, client_id=config['SPOTIPY_CLIENT_ID'], client_secret=config['SPOTIPY_CLIENT_SECRET'], redirect_uri=config['SPOTIPY_REDIRECT_URI'] ))这个scope参数表示我们需要三种权限:
- 读取收藏歌曲
- 读取个人排行榜
- 读取近期播放历史
首次运行时会自动打开浏览器完成授权。
3.2 获取核心听歌数据
创建data_fetcher.py:
def get_recent_tracks(sp, limit=50): """获取最近播放的歌曲""" results = sp.current_user_recently_played(limit=limit) return [{ 'played_at': item['played_at'], 'name': item['track']['name'], 'artist': ', '.join([a['name'] for a in item['track']['artists']]), 'duration_ms': item['track']['duration_ms'], 'id': item['track']['id'] } for item in results['items']] def get_top_items(sp, type='tracks', time_range='medium_term', limit=50): """获取排行榜数据""" return sp.current_user_top_items( type=type, time_range=time_range, limit=limit )3.3 获取音频特征数据
Spotify为每首歌提供了丰富的音频特征:
def get_audio_features(sp, track_ids): """批量获取音频特征""" features = [] for i in range(0, len(track_ids), 50): batch = track_ids[i:i+50] features += sp.audio_features(batch) return features关键音频特征说明:
danceability:节奏感 (0-1)energy:能量感 (0-1)valence:情绪积极度 (0-1)tempo:BPM速度loudness:响度 (dB)acousticness:原声程度 (0-1)
4. 数据分析与可视化
4.1 听歌时间模式分析
创建时间分布分析函数:
import pandas as pd from matplotlib import pyplot as plt def analyze_listening_times(df): # 转换时间戳 df['played_at'] = pd.to_datetime(df['played_at']) df['hour'] = df['played_at'].dt.hour df['day_of_week'] = df['played_at'].dt.dayofweek # 绘制小时分布 plt.figure(figsize=(10,5)) df['hour'].value_counts().sort_index().plot( kind='bar', color='#1DB954' ) plt.title('听歌时间分布(小时)') plt.xlabel('小时') plt.ylabel('播放次数') plt.savefig('listening_hours.png')4.2 音乐偏好雷达图
创建音频特征可视化:
import numpy as np def plot_audio_profile(features_df): categories = ['danceability', 'energy', 'speechiness', 'acousticness', 'instrumentalness', 'valence'] stats = features_df[categories].mean().tolist() stats += stats[:1] # 闭合雷达图 angles = np.linspace(0, 2*np.pi, len(categories), endpoint=False).tolist() angles += angles[:1] fig, ax = plt.subplots(figsize=(6,6), subplot_kw={'polar': True}) ax.fill(angles, stats, color='#1DB954', alpha=0.25) ax.plot(angles, stats, color='#1DB954', linewidth=2) ax.set_xticks(angles[:-1]) ax.set_xticklabels(categories) ax.set_title('你的音乐DNA', pad=20) plt.savefig('audio_profile.png')4.3 艺术家网络关系图
分析艺术家合作模式:
import networkx as nx def build_artist_network(df): G = nx.Graph() # 添加节点(艺术家) all_artists = set() for artists in df['artist'].str.split(', '): all_artists.update(artists) for artist in all_artists: G.add_node(artist) # 添加边(合作) for _, row in df.iterrows(): artists = row['artist'].split(', ') if len(artists) > 1: for i in range(len(artists)): for j in range(i+1, len(artists)): if G.has_edge(artists[i], artists[j]): G[artists[i]][artists[j]]['weight'] += 1 else: G.add_edge(artists[i], artists[j], weight=1) # 绘制网络 plt.figure(figsize=(12,12)) pos = nx.spring_layout(G) nx.draw_networkx_nodes(G, pos, node_size=50) nx.draw_networkx_edges(G, pos, alpha=0.2) nx.draw_networkx_labels(G, pos, font_size=8) plt.title('艺术家关系网络') plt.savefig('artist_network.png')5. 高级分析与应用
5.1 听歌情绪时间线
结合音频特征创建情绪分析:
def plot_mood_timeline(df, features_df): # 合并时间与特征数据 mood_df = pd.concat([ df[['played_at']], features_df[['valence', 'energy']] ], axis=1) # 计算7天移动平均 mood_df['valence_smooth'] = mood_df['valence'].rolling(7).mean() mood_df['energy_smooth'] = mood_df['energy'].rolling(7).mean() # 绘制双轴图 fig, ax1 = plt.subplots(figsize=(12,6)) ax2 = ax1.twinx() ax1.plot(mood_df['played_at'], mood_df['valence_smooth'], color='#1DB954', label='情绪') ax2.plot(mood_df['played_at'], mood_df['energy_smooth'], color='#191414', label='能量') ax1.set_ylabel('情绪值', color='#1DB954') ax2.set_ylabel('能量值', color='#191414') plt.title('听歌情绪时间线') plt.legend() plt.savefig('mood_timeline.png')5.2 创建个性化推荐系统
基于听歌历史生成推荐:
def get_recommendations(sp, seed_tracks, limit=10): return sp.recommendations( seed_tracks=seed_tracks, limit=limit, target_danceability=0.7, target_energy=0.6 )5.3 导出分析报告
使用Jinja2生成HTML报告:
from jinja2 import Environment, FileSystemLoader def generate_report(analysis_results): env = Environment(loader=FileSystemLoader('.')) template = env.get_template('report_template.html') html = template.render( top_artists=analysis_results['top_artists'], top_tracks=analysis_results['top_tracks'], audio_features=analysis_results['audio_features'] ) with open('music_report.html', 'w') as f: f.write(html)6. 常见问题与优化建议
6.1 API调用限制处理
Spotify API有速率限制(每分钟约300次请求),建议:
import time def safe_api_call(func, *args, **kwargs): try: return func(*args, **kwargs) except spotipy.exceptions.SpotifyException as e: if e.http_status == 429: retry_after = int(e.headers.get('Retry-After', 5)) print(f"达到限制,等待{retry_after}秒") time.sleep(retry_after) return safe_api_call(func, *args, **kwargs) raise6.2 数据存储策略
建议使用SQLite持久化数据:
import sqlite3 def init_db(): conn = sqlite3.connect('spotify_data.db') c = conn.cursor() c.execute('''CREATE TABLE IF NOT EXISTS listening_history (id TEXT PRIMARY KEY, played_at TEXT, name TEXT, artist TEXT, duration_ms INTEGER)''') conn.commit() return conn6.3 提升分析深度的技巧
结合外部数据:
- 用last.fm API补充标签数据
- 接入天气API分析天气对听歌影响
高级分析方法:
from sklearn.cluster import KMeans def cluster_songs(features_df): # 选择特征列 X = features_df[['danceability', 'energy', 'valence']] # 标准化 X = (X - X.mean()) / X.std() # K-means聚类 kmeans = KMeans(n_clusters=3) features_df['cluster'] = kmeans.fit_predict(X) return features_df自动化部署方案:
- 使用Apache Airflow设置每日自动分析
- 通过FastAPI创建个人分析仪表盘
7. 完整项目架构建议
spotify-analysis/ ├── config.json ├── auth.py ├── data/ │ ├── raw/ │ └── processed/ ├── analysis/ │ ├── time_analysis.py │ ├── audio_analysis.py │ └── network_analysis.py ├── utils/ │ ├── storage.py │ └── visualization.py ├── main.py └── requirements.txt实现main.py作为入口点:
from auth import get_spotify_client from data_fetcher import get_recent_tracks, get_audio_features from analysis.time_analysis import analyze_listening_times def main(): sp = get_spotify_client() # 获取数据 recent_tracks = get_recent_tracks(sp) track_ids = [t['id'] for t in recent_tracks] features = get_audio_features(sp, track_ids) # 分析数据 analyze_listening_times(pd.DataFrame(recent_tracks)) if __name__ == "__main__": main()这个项目最有趣的部分在于,随着你持续运行分析脚本,会逐渐发现一些自己都没意识到的听歌模式。比如我自己就发现,每逢阴雨天总会不自觉地播放更多独立民谣,而周五下午的能量饮料时间则固定会出现电子音乐——这些隐藏在数据中的行为模式,才是音乐分析最迷人的地方。