requests默认自动跟随重定向,response.url是最后一次成功响应的URL,但不可靠:因网络中断、JS跳转、meta refresh或服务端错误,该URL未必是用户浏览器最终到达的真实地址。

requests 默认会自动跟随重定向,但最终 URL 需要显式获取——不能只看 response.url,得确认是否真的走到了终点。
为什么 response.url 不一定可靠?
当请求中途被 302 或 301 重定向,requests 默认开启 allow_redirects=True(默认值),会一路跳转直到 2xx 或失败。表面看 response.url 就是最终地址,但有例外:
- 中间某次响应返回了
Location头,但后续跳转因网络中断、超时或服务端错误而终止,此时response.url是最后一次成功响应的 URL,不一定是“落地页” - 目标站用 JS 跳转(如
window.location.href),requests完全不执行 JS,response.url仍是 HTML 返回时的地址,和用户浏览器看到的最终 URL 不一致 - 某些反爬站点在 302 后返回 200 HTML,但内容里嵌了 meta refresh 或 JS 跳转,
response.url无法反映这个逻辑跳转
用 requests.Session().resolve_redirects() 手动控制跳转链
想确保拿到每一步的 URL 并判断是否真正落地,别依赖自动跳转,改用手动展开重定向链:
- 设置
allow_redirects=False发起首次请求 - 检查响应状态码是否为 301/302/307/308,若不是,当前
response.url就是落地 URL - 若是重定向,从
response.headers.get('Location')提取下跳地址,注意:该地址可能是相对路径,需用urllib.parse.urljoin(response.url, location)补全 - 重复请求,直到状态码非重定向类,或达到最大跳转次数(防环)
示例关键逻辑:
立即学习“Python免费学习笔记(深入)”;
from urllib.parse import urljoin
import requests
<p>def get_final_url(url, max_redirects=5):
session = requests.Session()
current<em>url = url
for </em> in range(max_redirects):
try:
r = session.get(current_url, allow_redirects=False, timeout=10)
if r.status_code not in (301, 302, 307, 308):
return r.url # 落地了
next_location = r.headers.get('Location')
if not next_location:
break
current_url = urljoin(r.url, next_location) # 处理相对路径
except Exception:
break
return current_url遇到 meta refresh 或 JS 跳转怎么办?
这类跳转不在 HTTP 协议层,requests 无能为力,必须解析 HTML 内容:
- 对响应内容调用
BeautifulSoup查找<meta http-equiv="refresh">标签,提取content中的url=...部分 - 简单正则也能应付大多数情况:
re.search(r'url[= ]*["\']([^"\']+)["\']', content) - JS 跳转更复杂,常见形式如
window.location.href = "..."或document.location = ...,可先用正则粗筛,再结合上下文判断是否为实际跳转逻辑(避免误抓注释或字符串字面量) - 注意:这些跳转可能带条件(如
if (condition) location.href=...),纯静态解析无法执行逻辑,只能当作“潜在跳转”处理,是否跟进取决于你的场景容忍度
要不要用 Selenium?权衡点在哪
如果目标网站重度依赖 JS 跳转,或跳转逻辑动态生成(如加密参数、时间戳校验),requests + BeautifulSoup 就会失效。这时 Selenium 确实能拿到真实浏览器看到的最终 URL:
- 启动
webdriver后访问初始 URL,等页面加载完成(driver.wait_until(...)),再读driver.current_url - 代价明显:启动慢、内存占用高、易被检测;且如果跳转后页面又触发新 JS 跳转(比如延迟 2 秒再跳),还得加等待逻辑
- 建议只在明确确认存在不可绕过 JS 跳转时启用,不要一上来就上 Selenium
- 更轻量的替代是
playwright或pyppeteer,它们对 headless 模式支持更好,API 更现代,但本质仍是浏览器自动化开销
真正难处理的,是那种重定向链里混着 HTTP 跳转 + meta refresh + JS 跳转的组合拳——这时候得按顺序逐层解析,每步都做 fallback 判断,而且必须设好跳转上限,否则容易卡死或陷入循环。


















