使用Spotipy获取Spotify数据:突破50条限制与解析方案问询
解决Spotipy批量数据获取与JSON解析效率问题
一、优化批量获取数据的逻辑
你当前的循环获取代码存在两个明显问题:固定循环次数可能遗漏数据,且直接保存完整response会导致后续解析需要多层嵌套操作。可以改成根据总条数动态循环,同时直接提取items存入列表,简化后续结构:
def get_all_liked_tracks(spot_obj): tracks = [] # 先获取第一页数据与总条数 first_page = spot_obj.current_user_saved_tracks(limit=50) total = first_page['total'] tracks.extend(first_page['items']) # 根据总条数计算循环次数,逐页获取数据 for offset in range(50, total, 50): page = spot_obj.current_user_saved_tracks(limit=50, offset=offset) tracks.extend(page['items']) return tracks
返回的tracks直接是所有歌曲的item列表,后续解析无需再处理多层嵌套的response结构。
二、简化JSON嵌套解析的方法
1. 封装辅助提取函数减少重复代码
针对嵌套字段的提取,可封装一个安全获取嵌套值的函数,避免KeyError同时简化代码:
def get_nested_value(data, keys, default=None): """安全获取嵌套字典的值""" current = data for key in keys: if isinstance(current, dict) and key in current: current = current[key] else: return default return current # 用辅助函数解析歌曲数据 song_list = [] for track_item in get_all_liked_tracks(spot_obj): song = get_nested_value(track_item, ['track', 'name'], '未知歌曲') artist = get_nested_value(track_item, ['track', 'album', 'artists', 0, 'name'], '未知歌手') album = get_nested_value(track_item, ['track', 'album', 'name'], '未知专辑') release = get_nested_value(track_item, ['track', 'album', 'release_date'], '未知日期') song_list.append((song, artist, album, release))
2. 用dataclass结构化数据(Python 3.7+)
如果需要更清晰的数据结构,可用dataclasses模块把解析后的歌曲数据封装成类对象,提升代码可读性与维护性:
from dataclasses import dataclass @dataclass class Song: name: str artist: str album: str release_date: str def parse_song(track_item): return Song( name=get_nested_value(track_item, ['track', 'name'], '未知歌曲'), artist=get_nested_value(track_item, ['track', 'album', 'artists', 0, 'name'], '未知歌手'), album=get_nested_value(track_item, ['track', 'album', 'name'], '未知专辑'), release_date=get_nested_value(track_item, ['track', 'album', 'release_date'], '未知日期') ) # 生成结构化的歌曲列表 song_objects = [parse_song(item) for item in get_all_liked_tracks(spot_obj)] # 访问示例:song_objects[0].name
3. 用Pydantic做严谨数据校验(进阶)
如果需要数据校验与自动类型转换,可使用Pydantic库,它能自动处理JSON到类对象的映射,同时处理缺失字段:
from pydantic import BaseModel, Field from typing import Optional class Artist(BaseModel): name: str class Album(BaseModel): name: str release_date: str artists: list[Artist] = Field(default_factory=list) class Track(BaseModel): name: str album: Album class SavedTrackItem(BaseModel): track: Track # 解析单条数据 def parse_song_pydantic(track_item): try: saved_track = SavedTrackItem(**track_item) # 处理歌手列表为空的边界情况 artist_name = saved_track.track.album.artists[0].name if saved_track.track.album.artists else '未知歌手' return Song( name=saved_track.track.name, artist=artist_name, album=saved_track.track.album.name, release_date=saved_track.track.album.release_date ) except Exception as e: print(f"解析失败: {e}") return None # 生成歌曲对象列表 song_objects = [song for song in map(parse_song_pydantic, get_all_liked_tracks(spot_obj)) if song]
三、整合到现有代码
把优化后的批量获取与解析逻辑整合到你的spot_dict中:
spot_obj = spotipy.Spotify(auth=token_info['access_token']) spot_dict = {} spot_dict['user'] = spot_obj.current_user() spot_dict['liked_songs'] = get_all_liked_tracks(spot_obj) spot_dict['playlists'] = spot_obj.current_user_playlists() # 播放列表也可套用类似批量获取逻辑 spot_dict['saved_albums'] = spot_obj.current_user_saved_albums() spot_dict['num_of_liked_songs'] = len(spot_dict['liked_songs'])
内容的提问来源于stack exchange,提问作者Nate
相关产品推荐
相关产品推荐

