B站扫码登录的接口设计
B站的扫码登录是各家里最规整的——接口语义清晰、无复杂加密,是理解扫码登录协议的最佳样本。核心目标:拿到 SESSDATA cookie(B站登录态的灵魂)。
全流程拆解
第一步:申请二维码
GET https://passport.bilibili.com/x/passport-login/web/qrcode/generate返回:
{
"data": {
"url": "https://passport.bilibili.com/h5-app/passport/login/scan?...qrcode_key=xxx",
"qrcode_key": "a1b2c3d4..."
}
}url 做成二维码展示(App 扫的就是它),qrcode_key 是后续轮询的凭证。
第二步:轮询扫码状态
GET https://passport.bilibili.com/x/passport-login/web/qrcode/poll?qrcode_key=xxx返回码含义:
86101:未扫码86090:已扫码,待确认86038:二维码已过期0:确认登录成功——此时响应头 Set-Cookie 里有 SESSDATA,同时data.url是跳转地址(老接口兼容)
第三步(可选):跳转激活
部分场景需要再 GET 一次 data.url 完成 cookie 的完整落地。用 Session 跟一次跳转即可。
完整实现
import requests, time, qrcode
class BiliQRLogin:
def __init__(self):
self.s = requests.Session()
self.s.headers['User-Agent'] = 'Mozilla/5.0 ...'
def login(self):
# 1. 申请二维码
r = self.s.get('https://passport.bilibili.com/x/passport-login/web/qrcode/generate')
data = r.json()['data']
qrcode_key, url = data['qrcode_key'], data['url']
# 2. 展示二维码(命令行打印或生成图片)
qr = qrcode.QRCode()
qr.add_data(url)
qr.print_ascii(invert=True)
# 3. 轮询
while True:
time.sleep(2)
r = self.s.get('https://passport.bilibili.com/x/passport-login/web/qrcode/poll',
params={'qrcode_key': qrcode_key})
code = r.json()['data']['code']
if code == 0:
print('登录成功')
return self.s.cookies.get('SESSDATA')
elif code == 86038:
print('二维码过期')
return None
elif code == 86090:
print('已扫码,待确认')精髓:SESSDATA 的使用与维护
- SESSDATA 是长期凭证(有效期约 30 天),但它只是登录 cookie 组合的核心——完整可用态还需要
bili_jct(CSRF token,写操作必备)、buvid3(设备标识)、DedeUserID(uid) - bili_jct 参与表单校验:POST 写操作(点赞、评论、投币)要带
csrf=bili_jct的值,从 cookie 取 - SESSDATA 有 IP 绑定倾向:频繁异地使用会触发"账号异常"验证。账号池里 SESSDATA 和 IP 段绑定
- 刷新机制:B站有 refresh_token 体系(
refresh_csrf/refresh_token接口),SESSDATA 快过期时无感刷新,别等失效了重新扫码
风控点
扫码登录接口本身风控宽松,但新登录态的"考察期"要注意:刚登录的会话立刻高频调接口,容易触发验证。登录后先访问几个页面接口"养"几分钟,再上业务请求。
总结
- 流程:generate 拿 qrcode_key → poll 轮询 → code=0 时收 SESSDATA
- 状态码 86101/86090/86038/0 对应等待/已扫/过期/成功
- SESSDATA + bili_jct + buvid3 是完整登录态,写操作要 csrf
- 新登录态有考察期,先养再用
交流微信:run1255