多数情况下不建议用Python重写JS解密逻辑,应优先复用浏览器环境(如Playwright)执行原JS获取参数;需注意JS执行时机、时间戳对齐、Math.random重写及全局状态依赖;对高混淆或反调试场景,可改用抓包复用合法sign。

JS解密参数在Python爬虫里到底要不要硬啃?
多数情况下,不建议直接用Python重写JS解密逻辑。JS里常混用混淆、时间戳依赖、WebAssembly、localStorage读取、canvas指纹等手段,用execjs或py_mini_racer跑原JS虽可行,但一旦JS更新(尤其带版本号或随机函数名),你的Python代码立刻失效。真正稳定的做法是复用浏览器环境本身。
用Playwright或Pyppeteer直接执行JS获取参数
这是目前最省心也最贴近真实请求的方式。关键不是“模拟”,而是“复用”——让目标页面的JS自己算出sign、token、ts这类参数,再把结果取出来。
- Playwright启动快、支持无头/有头切换,推荐优先选它:
from playwright.sync_api import sync_playwright<br>with sync_playwright() as p:<br> browser = p.chromium.launch(headless=True)<br> page = browser.new_page()<br> page.goto("https://example.com/api")<br> sign = page.evaluate("() => window.generateSign()") # 调用页面已加载的JS函数 - 注意
page.evaluate()只能访问当前页面上下文,如果解密函数在iframe或动态加载的script里,得先page.wait_for_function()确认函数存在 - 别在
page.goto()后立刻evaluate,JS可能还没执行完;加page.wait_for_timeout(500)或监听networkidle更稳妥
提取JS逻辑时最容易漏掉的三个依赖点
就算你决定用Python重写JS解密,也大概率卡在这三处:
-
Date.now()或new Date().getTime():Python里必须用int(time.time() * 1000),毫秒级对齐,差1ms都可能验签失败 -
Math.random()被重写了:有些站点会覆盖Math.random为确定性伪随机(比如基于时间+字符串seed),不能直接用Python的random.random() - 全局变量或闭包状态:比如
window.__a是上一步请求返回后由JS设置的,没发前序请求就调用解密函数,结果必错
什么时候该放弃JS逆向,改走代理或抓包?
如果目标接口只在登录后高频调用,且每次请求都带X-Signature和X-Timestamp,但JS里解密函数嵌套深、带调试陷阱(如debugger、setTimeout死循环)、还检测chrome.runtime,这时候硬刚JS就是浪费时间。
立即学习“Python免费学习笔记(深入)”;
- 用Charles或mitmproxy抓登录后的合法流量,提取加密逻辑的输入输出样本,反推规律
- 配合
requests.Session()复用cookie和header,把sign参数当成黑盒——只要Session没过期,就直接复用上一次成功请求里的sign值(适用于时效宽松的场景) - 某些站点的
sign其实只校验时间窗口(比如5分钟内有效),这时你可以缓存一个有效sign,配合本地时间戳生成新请求,绕过JS执行
JS解密不是非得“看懂”,而是“拿到结果”。路径选错,花三天写的Python版AES反而不如一行page.eval_on_selector来得稳。


















