js混淆加密需还原执行环境,常用execjs调用node.js运行纯逻辑js,依赖浏览器api时用playwright等无头浏览器;关键注意时间戳精度、编码一致性和随机因子来源。

JS混淆加密通常不是“绕过”,而是还原执行环境
直接用 requests 拿不到真实数据,是因为目标网站把关键参数(比如 sign、token、timestamp)通过 JS 动态生成,且代码被混淆(如变量名全为 _0xabc123、控制流扁平化、字符串数组+偏移解密)。你没法“跳过”它,只能让 Python 能跑通那段 JS 逻辑。
- 最常用且稳定的方式是用
execjs或PyExecJS调用本地 Node.js 执行混淆后的 JS 片段(前提是 JS 不依赖 DOM 或浏览器 API) - 如果 JS 里用了
document、localStorage、WebSocket等前端专属对象,就得上无头浏览器,比如playwright或selenium启动真实 Chromium 实例 - 别指望正则硬解混淆字符串数组——不同站点的混淆策略差异大,今天写的正则,明天更新就失效
用 execjs 运行简单混淆 JS 的实操要点
适用于:混淆只涉及基础运算、字符串拼接、AES/MD5/HMAC 等纯函数式加密,无浏览器环境依赖。
- 先确认 JS 代码能独立运行:把混淆脚本复制出来,在 Node.js 命令行里执行
node -e "your_js_code",看是否报错(常见错如ReferenceError: window is not defined) - 安装依赖:
npm install crypto-js(如果 JS 用了CryptoJS),再用pip install PyExecJS - Python 中调用时,注意传参方式:混淆 JS 通常导出一个函数,比如
function genSign(a, b) { ... },需用ctx.eval("genSign('foo', 'bar')"),不能直接ctx.call除非函数已挂到全局 - 避免每次请求都新建上下文——
execjs.compile()开销不小,建议复用ctx实例,或用lru_cache缓存编译结果
当 JS 依赖浏览器行为时,playwright 比 selenium 更轻量可靠
比如需要模拟鼠标滚动触发懒加载、读取 navigator.plugins、执行 eval 动态 script 标签内容等场景,playwright 启动快、API 更简洁,且默认禁用图片/字体加载可提速。
- 不要用
page.content()获取整个 HTML 再解析——混淆逻辑可能在page.evaluate()里动态计算,直接在页面上下文中执行更安全 - 示例:获取混淆后生成的
sign值:sign = await page.evaluate('''() => { // 把混淆 JS 的核心逻辑粘贴进来,或调用已有函数 return window.genSign(Date.now(), "api_path"); }''') - 记得设置
user_agent和viewport,部分混淆检测会查navigator.webdriver或屏幕尺寸,playwright默认为True,需手动设bypass_csp=True和user_agent伪装
混淆代码逆向的三个容易被忽略的细节
多数人卡在“JS 跑通了但 sign 总错”,往往不是算法问题,而是环境细节没对齐。
- 时间戳精度:混淆函数可能用
Date.now(),但服务端校验的是秒级或毫秒级,Python 传过去得统一用int(time.time() * 1000),别漏乘 1000 - 字符编码:JS 的
encodeURIComponent对空格编码为%20,而 Python 的urllib.parse.quote默认是+,要加参数safe=''才一致 - 随机因子来源:有些混淆会读
Math.random()、performance.now()甚至new Date().getMilliseconds(),这些值在服务端无法复现,必须从浏览器上下文里实时取,不能在 Python 里自己生成
混淆逻辑越深,越要分清哪些该在浏览器里做、哪些可抽离到 Python。强行全搬回 Python 解密,短期省事,长期维护成本高;完全依赖无头浏览器,又慢又重。真正稳定的方案,往往是两者混合:浏览器只负责拿“活”的输入(时间、随机数、DOM 状态),核心算法仍放在 Python 里可控执行。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











