
Puppeteer 的 page.evaluate() 运行在浏览器上下文中,无法直接访问 Node.js 环境中的函数;需通过 page.exposeFunction() 将函数安全注入页面全局作用域后方可调用。
在 puppeteer 中使用 `page.evaluate()` 时,若尝试将 node.js 环境定义的函数(如字符串解析工具 `parsetonumber`)作为参数传入,会报错 “xxx is not a function”——这是因为 `evaluate()` 的执行环境完全隔离于 node.js,所有传入参数都会被序列化(json 化),而函数无法被序列化,自然丢失。
要让自定义逻辑在浏览器端可用,推荐方案是使用 page.exposeFunction():它将 Node.js 函数注册为页面 window 对象上的全局可调用方法,且支持异步函数、保持作用域与错误传播能力。
✅ 正确做法如下:
const puppeteer = require('puppeteer');
async function getData() {
const browser = await puppeteer.launch({
headless: false,
slowMo: 100,
defaultViewport: { width: 1280, height: 1024 }
});
const page = await browser.newPage();
// ✅ 步骤1:定义并暴露函数(注意:函数名必须是字符串,且不能含空格或特殊字符)
const parseToNumber = (inputString) => {
const cleanedString = inputString.replace(/[^0-9a-zA-Z]+/g, '');
return parseInt(cleanedString, 10) || 0; // 显式指定基数,避免隐式转换风险
};
await page.exposeFunction('parseToNumber', parseToNumber);
// ✅ 步骤2:在 evaluate 中直接调用暴露后的全局函数(无需传参!)
await page.goto('MY_URL', { waitUntil: 'networkidle0' });
const result = await page.evaluate(() => {
return parseToNumber('2,42$'); // ✅ 成功调用,返回 242
});
console.log('Parsed number:', result); // 输出: 242
await browser.close();
}
getData().catch(console.error);
⚠️ 注意事项:
- exposeFunction() 注册的函数名(第一个参数)必须是合法的 JavaScript 标识符(如 'parseToNumber'),且在页面中会挂载为 window.parseToNumber;
- 暴露的函数不能访问 Node.js 闭包变量(如外部 const config = {...}),如需传递配置,请显式通过 evaluate() 参数传入原始值;
- 若函数为 async,evaluate() 内部需用 await 调用,且 evaluate() 本身也需 await;
- 不要在循环中重复调用 exposeFunction() 同一名字,否则会覆盖或报错;
- 替代方案(不推荐):将函数体作为字符串拼接进 evaluate()(易出错、无类型检查、调试困难)。
? 总结:page.exposeFunction() 是 Puppeteer 官方推荐的跨环境函数桥接方式,兼顾安全性、可维护性与调试友好性。务必优先使用它替代“序列化函数”的错误思路。










