使用Spotify API获取播放列表歌曲时数量缺失的问题求助
解决Spotify API获取播放列表歌曲数量不全的问题
问题描述
调用Spotify API获取指定播放列表的歌曲名称时,返回的歌曲数量总是随机少于实际总数(例如222首的列表只返回214首,152首的列表只返回125首)。尝试降低单次请求的limit值,问题仍未解决。
问题代码
@app.route("/bloom_songs") def display_songs(): id = "4AOXvSwX0XGg1cOPZxCa0t" # tracks.extend(data.get("items", [])) lists = display_songs(id) return lists # jsonify(lists) def get_num_of_songs(id): if "access_token" not in session: return redirect("/login") if datetime.now().timestamp() > session["expires_at"]: return redirect("/refresh-token") headers = {"Authorization": f"Bearer {session['access_token']}"} response = requests.get(API_BASE_URL + "me/playlists", headers=headers) playlists = response.json() for playlist in playlists["items"]: if playlist["id"] == id: total_songs = int(playlist["tracks"]["total"]) return total_songs def display_songs(id): if "access_token" not in session: return redirect("/login") if datetime.now().timestamp() > session["expires_at"]: return redirect("/refresh-token") headers = {"Authorization": f"Bearer {session['access_token']}"} total_songs = get_num_of_songs(id) loop_times = 100 total_requests = math.ceil(total_songs / loop_times) song_names = [] i = 0 while i < total_requests: try: response = requests.get( f"{API_BASE_URL}playlists/{id}/tracks?limit={loop_times}&offset={i*loop_times}", headers=headers, ) data = response.json() # Check if the response contains items if "items" in data: for song in data["items"]: song_names.append(song["track"]["name"]) i += 1 else: song_names.append("error") except Exception as e: print(f"Error fetching data: {e}") break song_names_json = json.dumps(song_names) return song_names_json
问题分析
- 同名函数冲突:路由函数
display_songs()和业务函数display_songs(id)重名,导致路由调用时触发参数错误,实际运行中可能出现递归或函数覆盖问题。 - 播放列表总数获取不可靠:
get_num_of_songs函数通过遍历me/playlists的结果获取目标列表的歌曲总数,但me/playlists接口本身有分页限制,如果目标列表不在第一页结果里,会直接返回未定义的total_songs,导致后续分页计算错误。 - 分页逻辑依赖预计算次数:通过
total_songs计算请求次数的方式不够可靠,Spotify API的分页应以返回结果中的next字段为准——如果next不为空,说明还有下一页数据需要获取,预计算次数可能因API返回异常、数据更新等原因导致遗漏。
修正方案
- 重命名路由函数,避免和业务函数冲突;
- 改用
next字段判断是否继续请求下一页,确保获取所有数据; - 增加对
track为None的判断(部分播放列表可能包含本地歌曲或无效条目,track字段会是None); - 强化错误处理,捕获HTTP请求级别的异常。
修正后的代码
from flask import redirect, session, jsonify import requests import datetime import json # 假设API_BASE_URL已定义,例如"https://api.spotify.com/v1/" @app.route("/bloom_songs") def bloom_songs_route(): # 重命名路由函数,避免冲突 playlist_id = "4AOXvSwX0XGg1cOPZxCa0t" result = fetch_playlist_songs(playlist_id) return result def fetch_playlist_songs(playlist_id): if "access_token" not in session: return redirect("/login") if datetime.now().timestamp() > session["expires_at"]: return redirect("/refresh-token") headers = {"Authorization": f"Bearer {session['access_token']}"} song_names = [] next_url = f"{API_BASE_URL}playlists/{playlist_id}/tracks?limit=100" while next_url: try: response = requests.get(next_url, headers=headers) response.raise_for_status() # 触发HTTP错误异常,比如401、429等 data = response.json() if "items" in data: for item in data["items"]: # 检查track是否存在,避免无效条目导致报错 if item.get("track"): song_names.append(item["track"]["name"]) # 更新next_url,判断是否还有下一页 next_url = data.get("next") except requests.exceptions.RequestException as e: print(f"请求错误: {e}") break except Exception as e: print(f"处理数据错误: {e}") break return json.dumps(song_names)
关键改进点
- 使用
next字段分页:完全遵循Spotify API的分页机制,确保不会遗漏任何一页数据; - 移除不可靠的总数预计算:不需要预先获取歌曲总数,直接通过
next字段判断是否继续请求; - 增加错误处理:使用
response.raise_for_status()捕获HTTP请求错误,比如令牌过期、请求频率超限等; - 处理无效条目:判断
track字段是否存在,避免因播放列表中的无效条目导致程序崩溃; - 函数名区分:路由函数和业务函数名称分开,避免冲突。
内容的提问来源于stack exchange,提问作者Zachary Hargett
相关产品推荐
相关产品推荐

