js2py不能替代puppeteer或pyexecjs,因其不支持dom、fetch等浏览器api且es6+兼容性差,仅适用于无dom的轻量同步js执行,如字符串处理或简单加密。

js2py 不能直接替代 Puppeteer 或 PyExecJS
js2py 是纯 Python 实现的 JS 解释器,适合轻量、同步、无 DOM 的 JS 执行场景。它不支持 window、document、fetch、setTimeout 等浏览器 API,也不兼容大部分现代 ES6+ 语法(如可选链 ?.、空值合并 ??、顶层 await)。爬虫中遇到带 DOM 操作或网络请求的混淆逻辑,用 js2py 会直接报错或结果错乱。
常见错误现象:ReferenceError: window is not defined、SyntaxError: Unexpected token 'const'、TypeError: Cannot read property 'xxx' of undefined。
- 适用场景:字符串拼接、Base64/Hex 编解码、简单异或/位运算、固定数组查表、AES/DES 密钥硬编码还原
- 不适用场景:动态生成
document.cookie、调用crypto.subtle.digest、解析依赖webpack运行时的混淆函数 - 性能影响:比 V8 引擎慢 10–50 倍,但启动零开销;适合单次执行、低频调用(如每次请求前生成 sign)
初始化 js2py 并执行简单混淆函数
核心是用 js2py.eval_js 或 js2py.compile_script 加载 JS 字符串,再传参调用。注意变量作用域隔离和类型转换——Python 字典传入后是 JS 对象,但 None 变成 null,True/False 变成 true/false,整数和浮点数精度可能丢失。
示例:某登录接口 sign 是 md5(timestamp + key).substr(0,16) 的 JS 实现:
import js2py
js_code = """
function genSign(ts, key) {
var str = ts + key;
return md5(str).substr(0, 16);
}
"""
# 需提前注入 md5 函数(js2py 自带,但需显式启用)
ctx = js2py.EvalJs()
ctx.execute(js_code)
result = ctx.genSign('1715678901', 'abc123') # 返回字符串
- 必须用
EvalJs()实例承载上下文,否则函数无法访问全局变量(如md5) - 若 JS 里用了
var声明但未赋值,js2py 默认设为undefined,不是None,后续调用可能静默失败 - 中文字符串传入需确保源码文件编码为 UTF-8,且 JS 字符串字面量本身不含 BOM,否则
eval_js会解析失败
处理含闭包或立即执行函数(IIFE)的混淆代码
很多前端加密逻辑封装在 IIFE 里,返回一个对象或函数。js2py 能解析,但要注意:IIFE 执行后的返回值默认丢弃,必须显式捕获;闭包内变量无法从外部读取,只能通过暴露的接口调用。
示例:一段返回加密函数的 IIFE:
js_code = """
(function() {
var s = 'salt_2024';
return {
encrypt: function(x) { return btoa(x + s); }
};
})()
"""
ctx = js2py.EvalJs()
ret = ctx.eval(js_code) # ret 是 JS 对象,不是 Python dict
encrypted = ret.encrypt('hello') # 正确调用
- 不能写
ctx.execute(js_code); ctx.encrypt(...)—— IIFE 的返回值没绑定到 ctx 上 -
ret.encrypt是 JS 函数,不能直接用 Python 的str参数传入,要确保类型匹配(比如数字传进去会被转成字符串) - 如果 IIFE 内部有
console.log,js2py 默认忽略;需手动 patchconsole对象才能捕获调试输出
绕过常见兼容性坑:ES5 降级与全局变量污染
js2py 对 ES5 支持较好,但对 let/const、for...of、箭头函数 兼容不稳定。最稳妥做法是把目标 JS 用 esbuild --target=es5 或在线工具预先降级;同时避免污染全局作用域——多次 execute 同一段 JS 会导致变量重复声明报错。
- 推荐做法:每次执行前新建
EvalJs()实例,或用ctx.reset()清空上下文 - 避免使用
with语句、eval字符串拼接,js2py 解析它们极不可靠 - 路径相关:如果 JS 里写了
require('./utils'),js2py 完全不支持 CommonJS 加载,必须手动提取并execute依赖代码 - 加密算法若依赖
crypto-js等库,别试图直接加载完整 CDN 版本——删掉所有if (typeof module !== 'undefined')和root.CryptoJS绑定逻辑,只保留核心函数体
复杂点在于:混淆 JS 往往混合了运行时检测(如 document.body 是否存在)、环境判断(process.env)、甚至反调试逻辑。这些在 js2py 里不是“执行不了”,而是“执行了但分支走错”,最终 sign 对不上。这时候得人工拆解控制流,而不是指望解释器自动适配。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











