个人音乐数据仪表盘:跨平台听歌记录分析与可视化
1. 项目概述:打造个人音乐数据仪表盘
去年整理硬盘时,偶然发现自己的音乐播放记录分散在五六个平台,突然萌生了个想法:要是能把这些数据统一分析,说不定能发现些有趣的听歌模式。这个项目就是通过抓取各平台的听歌记录,建立个人音乐数据库,实现三个核心功能:
- 自动统计每周/月/年的听歌总时长
- 可视化展示不同时段的听歌偏好变化
- 基于音频特征分析音乐风格分布
我最终实现的系统每周自动生成这样的报告:"上周共聆听14小时37分钟,工作日平均每天2小时,周末达3.5小时。电子音乐占比提升12%,特别是周五晚间出现Trance音乐高峰期。"
2. 数据采集方案设计
2.1 主流平台API对接
各大音乐平台都提供了开发者接口,但权限和数据结构差异较大:
| 平台 | 接口类型 | 关键字段 | 获取难度 |
|---|---|---|---|
| Spotify | Web API | track, duration, played_at | ★★☆☆☆ |
| 网易云音乐 | 私有API | song, playTime, source | ★★★★☆ |
| Apple Music | Apple MusicKit | playDate, songDuration | ★★★☆☆ |
| Last.fm | Scrobbler API | artist, track, timestamp | ★★☆☆☆ |
实操建议:优先从Last.fm入手,它记录了跨平台的播放历史。网易云需要抓包分析手机端接口,建议使用Charles等工具。
2.2 本地音乐文件处理
对于本地存储的MP3/FLAC文件,我用Python的mutagen库提取ID3标签:
from mutagen.id3 import ID3 audio = ID3("song.mp3") print({ 'title': audio.get('TIT2').text[0], 'artist': audio.get('TPE1').text[0], 'duration': audio.info.length })3. 核心分析模块实现
3.1 时长统计逻辑
关键是要处理不同来源的时间格式统一问题。比如Spotify返回的是ISO 8601格式("2023-07-15T14:30:22Z"),而网易云是Unix时间戳(毫秒级):
def normalize_time(time_str): if isinstance(time_str, int): # 处理时间戳 return datetime.fromtimestamp(time_str/1000) elif 'T' in time_str: # 处理ISO格式 return datetime.strptime(time_str, '%Y-%m-%dT%H:%M:%SZ') else: return datetime.strptime(time_str, '%Y-%m-%d %H:%M:%S')3.2 音乐风格分析方案
我测试了两种技术路线:
- 基于标签的分类:利用Last.fm的track.getTopTags方法
- 基于音频特征的聚类:使用librosa提取MFCC特征后做K-means聚类
实测发现第一种方案准确度更高,特别是对于中文歌曲。以下是特征提取代码片段:
import librosa y, sr = librosa.load('song.mp3') mfcc = librosa.feature.mfcc(y=y, sr=sr, n_mfcc=13)4. 可视化与报告生成
4.1 听歌时段热力图
用Plotly生成交互式热力图,清晰展示不同时段的听歌强度:
import plotly.express as px fig = px.density_heatmap( df, x="hour", y="weekday", z="duration", histfunc="sum" ) fig.update_layout(title='Weekly Listening Pattern')4.2 风格偏好雷达图
将音乐风格占比数据转化为六维雷达图,突出偏好变化:
| 时间周期 | 流行 | 摇滚 | 电子 | 古典 | 嘻哈 | 爵士 |
|---|---|---|---|---|---|---|
| 2023年第1周 | 35% | 20% | 15% | 10% | 15% | 5% |
| 2023年第2周 | 30% | 25% | 18% | 8% | 12% | 7% |
5. 踩坑实录与优化建议
- 时区问题:某次发现周末数据异常,原来是网易云返回的是北京时间戳,而Spotify是UTC时间。解决方案:
# 统一转换为本地时区 from pytz import timezone beijing = timezone('Asia/Shanghai') utc_time.replace(tzinfo=timezone('UTC')).astimezone(beijing)- 歌曲去重:不同平台对同一首歌的命名差异很大(比如包含/不包含feat信息),我最终采用fuzzywuzzy进行模糊匹配:
from fuzzywuzzy import fuzz if fuzz.ratio(title1, title2) > 85: # 判定为同一歌曲- 性能优化:当记录超过10万条时,Pandas处理明显变慢。这两个技巧很有效:
- 将datetime列转为period类型
- 对artist列使用category数据类型
这个项目最让我意外的发现是:每当项目截止日前三天,我的电子音乐收听量会暴涨200%。看来大脑在高压状态下确实需要特定类型的音乐刺激。现在我会根据这些数据主动调整播放列表,比如周一下午安排些轻音乐对抗"周一综合征"。
