使用Python requests库获取URL三次重定向后目标地址的问题
问题分析与解决方案
你遇到的核心问题是:你要获取的第三个URL是浏览器端的哈希(#)跳转,这种跳转完全在浏览器内部完成,不会向服务器发送HTTP请求,而requests作为纯HTTP请求库,只能处理服务器端的3xx重定向,无法捕获浏览器端的跳转行为。
为什么requests拿不到目标URL?
Spotify的response_type=token属于Implicit Grant Flow,这个授权流程是专门为前端应用设计的:
- 用户登录授权后,Spotify的服务器会返回一个包含
#access_token=xxx的跳转指令,但这个指令是让浏览器自己跳转到你的redirect_uri并把token放在哈希部分——哈希部分不会被发送到服务器,所以requests根本看不到这个跳转,它只能拿到服务器返回的登录页面(状态码200)。
解决方案1:用无头浏览器模拟真实浏览器行为
既然目标跳转是浏览器端的,我们可以用无头浏览器(比如Playwright或Selenium)模拟真实用户操作,这样就能捕获到跳转后的完整URL。
示例代码(Playwright):
首先安装依赖:
pip install playwright playwright install chromium
然后编写代码:
from playwright.sync_api import sync_playwright from urllib.parse import urlparse, parse_qs def get_spotify_final_url(initial_url): with sync_playwright() as p: # 启动无头浏览器(headless=False可以看到可视化窗口,方便调试) browser = p.chromium.launch(headless=True) page = browser.new_page() # 导航到初始URL,这里需要处理Spotify的登录 # 如果是本地测试,你可以先手动登录一次,让浏览器保存Cookie,避免重复登录 page.goto(initial_url) # 等待页面跳转到你的redirect_uri(带#token的URL),超时时间设为30秒 page.wait_for_url("http://0.0.0.0:7000/#*", timeout=30000) # 获取最终的完整URL final_url = page.url print("最终URL:", final_url) # 解析提取access_token parsed_url = urlparse(final_url) token_params = parse_qs(parsed_url.fragment) access_token = token_params.get("access_token", [""])[0] print("提取到的Access Token:", access_token) browser.close() return final_url # 替换成你的初始授权URL SPOTIFY_USER_ACCESS = "你的初始Spotify授权URL" get_spotify_final_url(SPOTIFY_USER_ACCESS)
解决方案2:改用Authorization Code Flow(更适合后端应用)
Implicit Grant Flow不适合后端服务使用,推荐改用Authorization Code Flow,这个流程是专门为后端设计的,不需要处理浏览器端的哈希跳转,直接通过后端请求获取token。
流程说明:
- 引导用户访问Spotify的授权URL,用户登录授权后,Spotify会将授权码(
code)发送到你的redirect_uri。 - 后端用这个
code+client_id+client_secret请求Spotify的token接口,直接拿到access_token。
示例代码:
import requests def get_access_token(code): client_id = "你的Spotify Client ID" client_secret = "你的Spotify Client Secret" redirect_uri = "http://0.0.0.0:7000/" token_endpoint = "https://accounts.spotify.com/api/token" payload = { "grant_type": "authorization_code", "code": code, "redirect_uri": redirect_uri, "client_id": client_id, "client_secret": client_secret } response = requests.post(token_endpoint, data=payload) response_data = response.json() if "access_token" in response_data: print("Access Token:", response_data["access_token"]) return response_data["access_token"] else: print("获取token失败:", response_data) return None # 替换成你获取到的授权码code(用户授权后从redirect_uri的参数中拿到) authorization_code = "用户授权后得到的code" get_access_token(authorization_code)
内容的提问来源于stack exchange,提问作者user12177026
相关产品推荐
相关产品推荐

