You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何获取Spotify播放列表全部曲目?Offset参数分页失效问题排查

分页失效问题解析与修复方案

嘿,我帮你找到了导致分页一直返回前100首的核心原因,还有几个代码里的小bug,咱们一步步梳理:

核心问题:错误解析Spotipy响应结构

这是分页失效的根本原因:你混淆了sp.playlist()sp.playlist_tracks()的返回结构!

  • sp.playlist_tracks()是专门用来获取播放列表曲目分页数据的接口,它返回的字典顶层直接包含total(总曲目数)和items(当前页曲目),根本没有嵌套的tracks键。
  • 但你的代码里错误地尝试从tracks_data['tracks']['total']tracks_data['tracks']['items']取值,这不仅会导致total无法被正确更新为实际总曲目数,还会让你每次都取不到正确的曲目数据(甚至可能抛出KeyError,除非你悄悄捕获了异常没写出来)。

其他需要修复的小问题

  1. 冗余的JSON序列化/反序列化sp.playlist_tracks()直接返回Python字典,完全没必要先用json.dumps转成字符串再用json.loads转回来,纯纯的多余操作。
  2. 未定义的row_num变量:代码里直接用了row_num但没初始化,运行时肯定会抛出NameError
  3. 文件管理不严谨:手动调用data_file.close()容易遗漏,最好用with语句自动管理文件生命周期。

修复后的完整代码

import spotipy, csv
from spotipy.oauth2 import SpotifyClientCredentials

# 替换成你的实际客户端ID和密钥
client_id = "your_client_id_here"
client_secret = "your_client_secret_here"

client_credentials_manager = SpotifyClientCredentials(client_id=client_id, client_secret=client_secret)
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)

# 使用with语句自动处理文件打开/关闭
with open('data.csv', 'w', newline='') as data_file:
    writer = csv.writer(data_file)
    writer.writerow(['track_num', 'track_id', 'track_name', 'first_artist', 'liked'])

    playlist_ids = [
        'xxxxxxxxxxxxxxxxxxxxxxx', # playlist 1
        'yyyyyyyyyyyyyyyyyyyyyyy' # playlist 2
    ]

    row_num = 1  # 初始化行号计数器
    for playlist_id in playlist_ids:
        offset_n = 0
        total_tracks = 0
        while True:
            # 显式指定limit=100(默认值也是100,写出来更清晰)
            tracks_response = sp.playlist_tracks(playlist_id, offset=offset_n, limit=100)
            total_tracks = tracks_response['total']
            current_page_tracks = tracks_response['items']
            
            # 如果当前页没有曲目,提前退出循环
            if not current_page_tracks:
                break
                
            for track_entry in current_page_tracks:
                # 处理特殊情况:部分曲目可能是本地文件,track字段为None
                if track_entry['track'] is None:
                    continue
                track_id = track_entry['track']['id']
                track_name = track_entry['track']['name']
                first_artist = track_entry['track']['artists'][0]['name']
                # 根据播放列表设置liked标记
                liked_status = 1 if playlist_id == playlist_ids[0] else 0
                writer.writerow([row_num, track_id, track_name, first_artist, liked_status])
                row_num += 1
            
            offset_n += 100
            # 当偏移量超过总曲目数时,终止分页循环
            if offset_n >= total_tracks:
                break

额外优化说明

  • 增加了对track_entry['track']None的判断,避免遇到本地文件或无效曲目时崩溃。
  • 用更清晰的变量名(比如total_trackscurrent_page_tracks)提升代码可读性。
  • 显式判断offset_n >= total_tracks来终止循环,逻辑更直观。

内容的提问来源于stack exchange,提问作者Ece Akdeniz

火山引擎 最新活动