如何用Python无需浏览器获取Spotify API认证重定向的最终URL
解决Spotify API授权码流程无浏览器获取回调URL的问题
问题本质
你拿到的登录URL属于Spotify OAuth2授权码流程的用户授权环节,这个环节必须经过用户登录+授权操作才能生成带code的回调URL。纯urllib或requests的HTTP请求无法模拟浏览器的登录交互(比如输入账号密码、处理Session/Cookie、验证码验证),所以直接请求只会返回登录页面,拿不到最终的回调链接。
可行解决方案
方案1:用无头浏览器模拟交互(推荐,适合本地开发)
用Playwright或Selenium这类无头浏览器工具,模拟真实浏览器的登录、授权操作,自动获取回调URL中的code。
以Playwright为例:
- 安装依赖:
pip install playwright playwright install chromium
- 示例代码:
from playwright.sync_api import sync_playwright import urllib.parse def get_spotify_code(): AUTH_URL = "你获取到的登录URL" REDIRECT_URI = "http://localhost:5000/" with sync_playwright() as p: browser = p.chromium.launch(headless=True) # 设为False可看到浏览器窗口 page = browser.new_page() page.goto(AUTH_URL) # 填写Spotify账号密码(替换为你的账号信息) page.fill('input[name="username"]', "你的Spotify邮箱/用户名") page.fill('input[name="password"]', "你的Spotify密码") page.click('button[type="submit"]') # 等待授权页面加载并点击授权按钮(首次授权会出现) page.wait_for_selector('button[data-testid="auth-accept"]') page.click('button[data-testid="auth-accept"]') # 等待跳转到回调URL page.wait_for_url(f"{REDIRECT_URI}*") # 提取URL中的code参数 current_url = page.url parsed_url = urllib.parse.urlparse(current_url) code = urllib.parse.parse_qs(parsed_url.query)['code'][0] browser.close() return code # 使用示例 spotify_code = get_spotify_code() print(f"获取到的授权code:{spotify_code}")
注意:如果Spotify触发验证码验证,需手动处理,或提前在浏览器登录后导出Cookie,让无头浏览器复用Cookie跳过登录步骤。
方案2:改用设备授权流程(无UI环境首选)
如果运行环境没有浏览器界面,推荐使用Spotify的设备授权流程(Device Authorization Flow),无需浏览器,仅需用户在其他设备上完成验证:
流程步骤:
- 向
https://accounts.spotify.com/api/device-authorization发送POST请求,携带client_id和scope - 获取
user_code(用户需输入的验证码)和verification_uri(用户验证的URL) - 提示用户访问
verification_uri并输入user_code - 轮询
https://accounts.spotify.com/api/token,直到拿到授权code或access_token
- 向
示例代码:
import requests import time CLIENT_ID = "你的Spotify Client ID" SCOPE = "playlist-modify-private" def device_auth_flow(): # 1. 获取设备授权信息 device_auth_url = "https://accounts.spotify.com/api/device-authorization" payload = { "client_id": CLIENT_ID, "scope": SCOPE } response = requests.post(device_auth_url, data=payload) device_data = response.json() user_code = device_data['user_code'] verification_uri = device_data['verification_uri'] interval = device_data['interval'] device_code = device_data['device_code'] print(f"请访问:{verification_uri}") print(f"输入验证码:{user_code}") # 2. 轮询获取授权 token_url = "https://accounts.spotify.com/api/token" while True: token_payload = { "client_id": CLIENT_ID, "device_code": device_code, "grant_type": "urn:ietf:params:oauth:grant-type:device_code" } token_response = requests.post(token_url, data=token_payload) token_data = token_response.json() if token_response.status_code == 200: print(f"授权成功!access_token:{token_data['access_token']}") break elif token_data['error'] == "authorization_pending": time.sleep(interval) elif token_data['error'] == "expired_token": print("验证码已过期,请重新发起请求") break else: print(f"授权失败:{token_data['error']}") break # 使用示例 device_auth_flow()
方案3:手动模拟登录(不推荐)
尝试用requests.Session保存Cookie,手动提取登录页面的CSRF token并模拟登录,但Spotify的登录页面有动态验证逻辑(比如reCAPTCHA),这个方法极易失效,仅作参考:
import requests import urllib.parse from bs4 import BeautifulSoup def simulate_login(): AUTH_URL = "你获取到的登录URL" SESSION = requests.Session() # 1. 获取登录页面,提取CSRF token login_page = SESSION.get(AUTH_URL) soup = BeautifulSoup(login_page.text, 'html.parser') csrf_token = soup.find('input', {'name': 'csrf_token'})['value'] # 2. 模拟登录请求 login_payload = { 'username': '你的账号', 'password': '你的密码', 'csrf_token': csrf_token, 'remember': 'true' } login_response = SESSION.post("https://accounts.spotify.com/login", data=login_payload) # 3. 访问授权页面,获取回调URL parsed_auth_url = urllib.parse.urlparse(AUTH_URL) continue_url = urllib.parse.parse_qs(parsed_auth_url.query)['continue'][0] authorize_response = SESSION.get(continue_url) # 检查是否跳转到回调URL if authorize_response.url.startswith("http://localhost:5000/"): parsed_callback = urllib.parse.urlparse(authorize_response.url) code = urllib.parse.parse_qs(parsed_callback.query)['code'][0] print(f"获取到code:{code}") else: print("登录失败或需要验证码") # 使用示例 simulate_login()
为什么之前的方法无效
urllib.request.urlopen(auth_request.url)只会发送一次HTTP请求,获取登录页面的内容,不会处理后续的用户登录、授权交互。Spotify的授权流程必须经过用户确认,纯HTTP请求无法完成这个环节,所以无法拿到带code的回调URL。
内容的提问来源于stack exchange,提问作者kenpino
相关产品推荐
相关产品推荐

