You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

问题分析

  1. 同名函数冲突:路由函数display_songs()和业务函数display_songs(id)重名,导致路由调用时触发参数错误,实际运行中可能出现递归或函数覆盖问题。
  2. 播放列表总数获取不可靠:get_num_of_songs函数通过遍历me/playlists的结果获取目标列表的歌曲总数,但me/playlists接口本身有分页限制,如果目标列表不在第一页结果里,会直接返回未定义的total_songs,导致后续分页计算错误。
  3. 分页逻辑依赖预计算次数:通过total_songs计算请求次数的方式不够可靠,Spotify API的分页应以返回结果中的next字段为准——如果next不为空,说明还有下一页数据需要获取,预计算次数可能因API返回异常、数据更新等原因导致遗漏。

修正方案

  1. 重命名路由函数,避免和业务函数冲突;
  2. 改用next字段判断是否继续请求下一页,确保获取所有数据;
  3. 增加对track为None的判断(部分播放列表可能包含本地歌曲或无效条目,track字段会是None);
  4. 强化错误处理,捕获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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 12:57:11