jwt鉴权需手动提取、存储与复用,不能自动处理;核心是用requests.session()统一管理token,解析exp提前刷新,并区分authorization头、cookie或自定义字段携带方式。

JWT鉴权通常不是“自动处理”,而是必须显式解析和携带
Python爬虫无法像浏览器那样自动管理JWT(比如 localStorage 里的 token 或自动附加 Authorization 头)。你看到的“自动”往往是误判——实际是手动提取、存储、复用。关键在于:JWT本身无状态,但它的生命周期、签名验证、刷新逻辑都得由你控制。
常见错误现象:401 Unauthorized 即使登录成功后仍频繁出现;403 Forbidden 返回但没提示原因;抓到的 Authorization: Bearer xxx 头在下个请求就失效。
- 先确认 JWT 是放在
Authorization请求头(最常见),还是Cookie,或自定义 header(如X-Auth-Token) - 检查响应中是否返回新 token(例如登录接口返回
{"token": "xxx"}或Set-Cookie带HttpOnly=false) - 注意 JWT 的
exp字段(单位秒),别拿一个 15 分钟前获取的 token 一直重用
用 requests.Session() 管理 token 最简可行方案
不用第三方库也能稳住基础流程:登录 → 提取 token → 注入后续所有请求。核心是复用 Session 对象,并手动设置 headers。
import requests
import json
<p>s = requests.Session()</p><h1>1. 登录获取 token</h1><p>login_resp = s.post("<a href="https://www.php.cn/link/052c3ffc93bd3a4d5fc379bf96fabea8">https://www.php.cn/link/052c3ffc93bd3a4d5fc379bf96fabea8</a>", json={"user": "a", "pass": "b"})
token = login_resp.json()["token"] # 或 resp.headers.get("X-Auth-Token")</p><h1>2. 统一注入 Authorization 头</h1><p>s.headers.update({"Authorization": f"Bearer {token}"})</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill6933" title="python-script-generator"><img
src="https://img.php.cn/upload/skill/000/000/081/179119443150703.jpg" alt="python-script-generator" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill6933" title="python-script-generator" class="overflowclass">python-script-generator</a>
<p class="overflowclass">快速生成专业的 Python 脚本和应用代码。一键创建完整项目结构,支持CLI、API、爬虫、Bot、Django等多种项目类型,包含完整的项目结构、配置文件、依赖管理、测试、README和文档。</p>
</div>
<a rel="nofollow" href="/xiazai/skill6933" title="python-script-generator" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div><h1>3. 后续所有请求自动带 token</h1><p>res = s.get("<a href="https://www.php.cn/link/46b315dd44d174daf5617e22b3ac94ca">https://www.php.cn/link/46b315dd44d174daf5617e22b3ac94ca</a>")
</p>
- 不要每次请求都重新生成
Session,否则 header 丢失 - 如果 API 要求 token 放在 Cookie,改用
s.cookies.set("auth_token", token) - 避免把 token 硬编码进 headers 字典字面量(如
{"Authorization": "Bearer xxx"}),会覆盖Session自带的其他 headers(如User-Agent)
遇到 token 过期时,别硬重试,要主动刷新
很多系统提供 /refresh 接口,但调用它往往需要旧 token 或 refresh_token。直接复用原 token 发请求失败后才去刷新,容易引发竞态或重复刷新。
更稳妥的做法:提前 30 秒检查 exp,过期前主动换新。可用 jwt.decode(token, options={"verify_signature": False})(仅用于读 exp,不验签)快速解析:
import jwt
import time
<p>def is_token_expired(token):
try:
payload = jwt.decode(token, options={"verify_signature": False})
return payload["exp"] </p><p>if is_token_expired(current_token):
refresh_resp = s.post("<a href="https://www.php.cn/link/847b226710934da24831bc40292c7523">https://www.php.cn/link/847b226710934da24831bc40292c7523</a>", json={"refresh_token": rt})
current_token = refresh_resp.json()["token"]
s.headers["Authorization"] = f"Bearer {current_token}"
</p>
- 别依赖服务器返回的
401触发刷新——有些接口返回200但 body 里写{"error": "token expired"} - refresh_token 通常比 access_token 生命周期长,但它也可能过期,需有兜底(比如回到登录页重走流程)
- 并发请求时,多个线程可能同时发现 token 过期并发起刷新,结果只有一个成功,其余拿到 401 ——加个简单锁或用单次刷新 + 缓存机制更安全
绕过前端 JS 生成的 JWT?基本不可行,别浪费时间
如果网站把 token 生成逻辑藏在混淆 JS 里(比如用 Web Crypto API 算 signature,或拼接动态 salt),requests 拿不到运行时上下文,就无法复现。这时候不是“怎么自动”,而是“不该自动”。
- 用
playwright或selenium启动真实浏览器,等 JS 执行完再取localStorage.getItem("token")或拦截 fetch/XHR 响应 - 检查是否真需要 JWT:有些数据接口其实走的是 Cookie 鉴权,登录后
Session自动维持即可,JWT 只用于特定管理后台 - 逆向 JS 成本高、维护难,且一旦前端更新算法,爬虫立刻瘫痪——优先看有没有未鉴权的备用接口,或联系对方申请 API 权限
真正麻烦的从来不是“怎么塞 token”,而是“token 怎么来”和“什么时候换”。前者卡在前端逻辑,后者卡在业务规则,这两处没理清,后面所有自动封装都是空中楼阁。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










