javascript-obfuscator混淆Puppeteer代码后报变量未定义错误如何解决
问题现象
代码未混淆时可正常运行,使用javascript-obfuscator混淆后执行失败,错误触发点为await page.content()行。
原始可运行代码:
const puppeteer = require('puppeteer-core'); let params = { ignoreHTTPSErrors: true, args: [ '--ignore-certificate-errors', '--no-sandbox', ], executablePath: this.chromePath, headless: true, }; const browser = await puppeteer.launch(params); var page = await browser.newPage(); await page.goto(this.url, { waitUntil: 'load' }); await page.waitForTimeout(2000); await page.content(); // 错误触发行 await page.setViewport({ width: 1600, height: 1200 }); await page.waitForTimeout(2000);
运行报错信息:
(node:22648) UnhandledPromiseRejectionWarning: Error: Evaluation failed: ReferenceError: _0xa28d is not defined at __puppeteer_evaluation_script__:1:21 at _0x1ce9f4._evaluateInternal (E:\xx\dist\bundle.js:1:3355462) at processTicksAndRejections (internal/process/task_queues.js:93:5) at async _0x1ce9f4.evaluate (E:\xx\dist\bundle.js:1:3353310) at async _0x23b99f.content (E:\xx\dist\bundle.js:1:3400665) at async _0x14d154.content (E:\xx\dist\bundle.js:1:3508435) at async _0x571581.getContentInaSinglePage (E:\xx\dist\bundle.js:1:4423286) at async _0x508402.isInteresting (E:\xx\dist\bundle.js:1:4622902) at async _0x508402.startScan (E:\xx\dist\bundle.js:1:4641280) at async _0x421a37.scan (E:\xx\dist\bundle.js:1:4643371) at async E:\xx\dist\bundle.js:1:4970734
问题根因
javascript-obfuscator默认会对全局作用域、所有依赖代码的标识符做统一重命名,将原生变量、函数名替换为_0xxxxx格式的混淆名称,但Puppeteer的page.content()、page.evaluate()这类API的底层逻辑,是将待执行的JS代码序列化后注入到独立的浏览器页面上下文运行,和本地Node.js运行时的上下文完全隔离。
混淆操作改写了Puppeteer内部注入逻辑引用的标识符,这些被重命名的_0xxxxx变量仅存在于本地Node侧的打包产物中,浏览器上下文内不存在对应定义,因此代码注入执行时直接抛出ReferenceError。
解决方案
- 配置混淆规则排除第三方依赖:在打包或混淆配置中,将
node_modules目录下的所有文件(尤其是puppeteer-core源码)加入排除列表,仅混淆自行编写的业务逻辑代码,不修改第三方依赖的标识符和执行逻辑,从根源避免跨上下文的变量名不匹配问题。 - 调整混淆强度与规则:不要使用最高等级混淆配置,针对Puppeteer项目使用低-中等级混淆即可,同时关闭以下容易破坏代码逻辑的规则:
- 关闭
renameGlobals,避免全局标识符被无差别重命名 - 关闭控制流平坦化、字符串数组加密等高侵入性规则,防止Puppeteer内部注入的代码字符串被篡改
- 配置
reservedNames规则,保留Puppeteer内部使用的相关标识符不被重命名
- 关闭
- 规范跨上下文代码写法:自行编写的需要注入浏览器执行的逻辑(如
page.evaluate的回调),不要直接引用Node侧作用域的变量,所有需要传递的参数通过API的入参字段传入,回调逻辑尽量保持独立,避免混淆器改写回调内的外部引用。
内容的提问来源于stack exchange,提问作者Homer Qing
相关产品推荐
相关产品推荐

