Spotipy调用.track(track_id)无报错阻塞 无法获取曲目数据问题
故障根因
你遇到的无响应不抛错问题,90%以上是以下几个原因导致的:
- Spotipy默认封装的requests请求没有设置超时时间,当出现网络链路抖动、目标接口节点连接挂死、个别资源查询请求不回包也不断开连接时,程序会永久阻塞在IO等待阶段,根本不会触发异常,你写的外层try-except完全接不住这类阻塞。之所以其他接口正常,是因为Spotify不同API对应的后端服务、CDN节点是独立部署的,track接口关联预览音频资源的节点近期路由调整、节点故障都可能触发这类挂死。
- 代码里用了裸
except:,就算是有可捕获的异常(比如部分失效ID返回的格式错误)也会被直接吞掉,连错误日志都打不出来,根本没法定位问题。 - 批量高频请求触发了Spotify的软限流:这类限流不会返回标准429错误码,只会直接hold住连接不返回任何数据,之前你能跑通是因为请求频次、总量还没到触发阈值。
- 你当前处理的批次里刚好存在区域受限、已下架的异常track_id,这类ID查询时偶发接口不响应的已知bug,之前批次里这类ID占比低没触发问题。
排查步骤
按顺序测试即可快速定位问题:
- 先用公开可访问的测试track_id(比如
4uLU6hMCjMI75M1A2tKUQC)单独写测试调用,手动给sp.track加10秒超时参数,看能不能正常返回,先排除全量服务故障。 - 打印你当前读取文件拿到的第一个track_id,单独调用接口测试,确认是不是某一个特定ID触发的挂死。
- 换个出口网络(比如切手机热点、换代理节点)跑同样的请求,如果恢复正常就是本地到Spotify节点的路由故障。
- 给请求加上日志,看请求发出后有没有收到响应头、响应体,确认是请求没发出去,还是发出去了没收到回包。
修复方案
核心要补超时、重试、错误日志三个能力,不要裸吞异常:
- 初始化Spotipy客户端时必须显式设置请求超时,避免永久挂死
- 配置自动重试和退避逻辑,应对偶发的网络抖动、限流
- 替换裸except,明确捕获超时、请求异常,打印错误信息方便排查
- 文件操作改用上下文管理器,避免异常时文件句柄泄漏,加实时刷盘避免程序中断丢数据
修复后的可运行代码:
import spotipy import time import requests from spotipy.oauth2 import SpotifyClientCredentials from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry # 构造带重试、超时配置的请求会话 def init_spotify_session(): session = requests.Session() # 重试规则:总重试3次,退避间隔0.5s/1s/2s,遇到服务端错误、限流自动重试 retry_config = Retry( total=3, backoff_factor=0.5, status_forcelist=[429, 500, 502, 503, 504], allowed_methods=["GET"] ) adapter = HTTPAdapter(max_retries=retry_config) session.mount("https://", adapter) return session # 替换成你自己的密钥,建议不要硬编码在代码里 cid = '121e03d3acd1440188ae4c0f58b844d4' secret = '431a5e56bcd544c3aefce8166a9c3703' client_credentials_manager = SpotifyClientCredentials(client_id=cid, client_secret=secret) sp = spotipy.Spotify( client_credentials_manager=client_credentials_manager, requests_session=init_spotify_session(), requests_timeout=10 # 核心配置:单请求10秒超时,避免永久挂死 ) number = 2 input_file = f'data/25k_data/track_url_{number}.txt' output_file = f'data/25k_data_preview/track_url_preview_{number}.txt' # 上下文管理器自动处理文件打开/关闭 with open(input_file, 'r', encoding='utf-8') as f_in, open(output_file, 'a', encoding='utf-8') as f_out: for line in f_in: track_id = line.strip() if not track_id: continue print(f"处理track_id: {track_id}") try: track_data = sp.track(track_id) preview_url = track_data.get('preview_url') if preview_url: f_out.write(f"{track_id} {preview_url}\n") f_out.flush() # 实时写入磁盘,避免程序崩溃丢已爬取的数据 # 加100ms请求间隔,避免触发限流 time.sleep(0.1) except requests.exceptions.Timeout: print(f"track {track_id} 请求超时,跳过") continue except Exception as e: print(f"track {track_id} 处理失败: {str(e)},跳过") continue
补充注意点:
- 如果加了超时后出现大量超时错误,优先换网络/代理节点,基本是本地到Spotify音频CDN的路由不通导致的
- 如果出现大量429错误,就把sleep间隔调大到0.5-1秒,降低请求频率
- 绝对不要用不指定异常类型的裸
except:,会吞掉所有错误包括键盘中断,排查问题的时候根本看不到报错信息
内容的提问来源于stack exchange,提问作者friendly_man
相关产品推荐
相关产品推荐

