整理B站链接时,经常能遇到 b23.tv 开头的短地址。想把它还原成完整的长链接,可能是为了存档、提取视频ID,或者只是想知道最终会跳到哪个页面。这类短链接本身只是一个跳转入口,真实地址要等服务端重定向后才能确定。用 Python 写个小工具来做这件事会很方便,让 requests 自动处理跳转就行。
比较直接的做法是发送 HEAD 请求。它只返回响应头,不下载页面正文,速度更快也更省流量。requests 默认会跟随重定向,所以大多数情况下不需要手动解析 Location。
可以这样封装一个函数:
import requests
def expand_b23_link(short_url: str) -> str:
"""把 B站短链接展开为最终长链接"""
try:
resp = requests.head(short_url, allow_redirects=True, timeout=10)
resp.raise_for_status()
return resp.url
except requests.RequestException as e:
print(f"请求出错:{e}")
return short_url
使用时把短链接传进去即可:
short = "https://b23.tv/example_short_link"
long_url = expand_b23_link(short)
print("展开后的链接是:", long_url)
这样拿到的
long_url 基本就是B站最终落地页地址。当然,有时候你可能不只是想要一个结果,还想知道中间到底跳了几次、跳去了哪里。这时可以关掉自动跟随,每次只发一次请求,再从响应头里读取
Location 字段,手动一层一层往下走。这种方式适合排查跳转链路异常,但要设置最大跳转次数,否则遇到环状重定向会一直循环。简化逻辑如下:
def manual_expand(url: str, max_hops: int = 5) -> str:
for _ in range(max_hops):
resp = requests.head(url, allow_redirects=False, timeout=10)
location = resp.headers.get("location")
if not location:
return resp.url or url
url = location
return url

不过对多数使用场景来说,
requests 自动跟随已经够用。展开之后,你可能会发现长链接里带了不少查询参数,像
spm_id_from、from_source 这类跟踪标识。如果只想要干净的基础链接,可以用正则把问号后面的内容去掉:import re
def clean_url(url: str) -> str:
match = re.match(r"^(https?://[^?]+)", url)
return match.group(1) if match else url
这个函数会保留协议、域名和路径,把查询参数全部删掉。例如:
https://www.bilibili.com/video/BV1xx411c7mD?spm_id_from=333.999会被处理成:

https://www.bilibili.com/video/BV1xx411c7mD如果只想删除部分参数,用
urllib.parse 来解析和过滤会更可靠,正则不是最佳选择。
实际使用时还要注意几件事。网络请求一定要设置超时,避免某个短链接长时间不响应把程序卡住。错误处理也必不可少,至少捕获
requests.RequestException,这样遇到 DNS 失败、连接超时或 HTTP 错误时,还能返回一个结果而不是直接崩溃。B站的链接格式和重定向策略可能会调整,如果发现展开结果不对,可以先在浏览器里手动确认跳转逻辑,再回来修改代码。另外,批量请求时尽量控制频率,并遵守平台的使用规则和隐私政策,不要把工具用于高频抓取或不当用途。这套流程覆盖了大部分日常需求:先拿到最终地址,再按需清理,基本就能满足归档、分析或后续处理。
지금 로그인