使用Spotify API获取当前播放歌曲时偶现KeyError及401权限缺失问题求助
问题描述
我正尝试使用Spotify API检索并打印我的账户中当前播放的歌曲。在代码完全未作任何改动的情况下,该功能有时正常运行,有时却失败。我收到的错误信息如下:
Traceback (most recent call last): File "main.py", line 64, in <module> main() File "main.py", line 22, in main current_track_info = get_current_track(SPOTIFY_ACCESS_TOKEN) File "main.py", line 50, in get_current_track track_name = resp_json['item']['name'] KeyError: 'item'
这个错误应该意味着未找到"item"字段,对吗?但我当时正在Spotify账户中播放音乐,并且刚获取并输入了全新的access token。该功能仅约10%的概率能正常运行,且代码始终无任何改动。使用相同的授权token在Spotify的Web控制台中可以正常工作,但在我自己的程序中却不行。在尝试相关代码后打印的JSON响应结果为:
{'error': {'message': 'Permissions missing', 'status': 401}}
以下是我的代码:
import requests from pprint import pprint SPOTIFY_GET_CURRENT_TRACK_URL = 'https://api.spotify.com/v1/me/player/currently-playing' ACCESS_TOKEN = '' def get_current_track(access_token): response = requests.get( SPOTIFY_GET_CURRENT_TRACK_URL, headers={"Authorization": f"Bearer {access_token}"} ) json_resp = response.json() track_id = json_resp['item']['id'] track_name = json_resp['item']['name'] artists = [artist for artist in json_resp['item']['artists']] link = json_resp['item']['external_urls']['spotify'] artist_names = ', '.join([artist['name'] for artist in artists]) current_track_info = { "id": track_id, "track_name": track_name, "artists": artist_names, "link": link } return current_track_info def main(): current_track_id = None while True: current_track_info = get_current_track(ACCESS_TOKEN) if current_track_info['id'] != current_track_id: pprint( current_track_info, indent=4, ) current_track_id = current_track_info['id'] if __name__ == '__main__': main()
我是Python和API的新手,任何帮助都将不胜感激!
问题分析与解决方案
1. 核心问题拆解
你遇到的KeyError: 'item'其实是个连锁问题:首先API返回了权限缺失的错误响应(就是你看到的Permissions missing),但你的代码完全没做错误处理,直接默认响应里一定有item字段,自然就触发了KeyError。
至于为什么Web控制台能用但自己的代码不行?大概率是你在控制台测试时,授权流程已经包含了接口所需的权限,但自己获取token时漏加了必要的权限范围(scope)。
2. 分步解决
(1)补全获取token时的权限范围
Spotify的/me/player/currently-playing接口必须要求user-read-currently-playing这个权限scope,如果你需要读取更详细的播放状态,还可以加上user-read-playback-state。
在获取access token的授权请求里,要把这些scope加进去,比如授权URL里需要包含:
scope=user-read-currently-playing%20user-read-playback-state
注意多个scope之间用%20(URL编码的空格)分隔,重新获取包含这些权限的token再测试。
(2)给代码添加错误处理逻辑
你的代码现在直接硬取json_resp['item'],完全没考虑API返回错误或者没有播放内容的情况,咱们来修改get_current_track函数:
def get_current_track(access_token): response = requests.get( SPOTIFY_GET_CURRENT_TRACK_URL, headers={"Authorization": f"Bearer {access_token}"} ) # 先检查响应状态码,非200直接处理错误 if response.status_code != 200: print(f"API请求失败,状态码: {response.status_code}") json_resp = response.json() if 'error' in json_resp: print(f"错误详情: {json_resp['error']['message']}") return None # 返回None表示获取失败 json_resp = response.json() # 额外检查是否有item字段(比如暂停播放时也可能没有item) if 'item' not in json_resp: print("当前没有正在播放的歌曲") return None track_id = json_resp['item']['id'] track_name = json_resp['item']['name'] artists = [artist for artist in json_resp['item']['artists']] link = json_resp['item']['external_urls']['spotify'] artist_names = ', '.join([artist['name'] for artist in artists]) current_track_info = { "id": track_id, "track_name": track_name, "artists": artist_names, "link": link } return current_track_info
(3)主循环适配错误情况
修改main函数,避免因为返回None而报错,同时加个延迟防止频繁请求被限流:
def main(): current_track_id = None while True: current_track_info = get_current_track(ACCESS_TOKEN) # 只有获取到有效信息且歌曲变化时才打印 if current_track_info is not None and current_track_info['id'] != current_track_id: pprint( current_track_info, indent=4, ) current_track_id = current_track_info['id'] # 每5秒检查一次,避免请求过于频繁 import time time.sleep(5)
3. 额外提示
如果之后还是偶尔出现问题,可以检查token是否过期——Spotify的access token默认有效期是1小时,需要用refresh token去刷新,不过如果是测试阶段,重新获取新的token也能临时解决。
内容的提问来源于stack exchange,提问作者Luke Sanford

