You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

尝试将util模块传入puppeteer page.evaluate失败求解决

解决Puppeteer中无法将Node.js util模块传入page.evaluate的问题

我明白你现在卡在把Node.js的util模块传到Puppeteer的page.evaluate里的问题了——这个坑我之前也踩过,毕竟浏览器上下文和Node.js上下文是完全隔离的,直接传模块对象肯定不行。你遇到的ReferenceError: util is not defined本质上就是因为这两个环境完全不互通,Node.js的模块没法直接在浏览器环境里使用。

为什么你之前找的方案可能没用?

很多旧方案可能尝试直接把util对象作为参数传给page.evaluate,但util是一个包含大量不可序列化属性的复杂对象(比如内部函数引用、非JSON兼容的状态),Puppeteer在序列化参数的时候会丢失这些内容,导致浏览器上下文里拿到的是个空对象或者直接是undefined,自然会报错。

可行的解决方法

方法1:用page.exposeFunction桥接需要的util方法

page.exposeFunction可以把Node.js端的函数暴露成浏览器上下文里的全局函数,这样你就能在page.evaluate里调用Node端的util方法了。比如你需要用util.format:

const puppeteer = require("puppeteer");
const util = require("util");
const path = "http://books.toscrape.com/";

(async () => {
  const browser = await puppeteer.launch({headless: false});
  const page = await browser.newPage();

  // 把Node端的util.format暴露给浏览器,命名为window.utilFormat
  await page.exposeFunction("utilFormat", (...args) => {
    return util.format(...args);
  });

  await page.goto(path, {waitUntil: "networkidle2"});

  const result = await page.evaluate(async () => {
    // 在浏览器上下文调用暴露的方法
    const bookTitle = document.querySelector("h1").textContent;
    return utilFormat("当前页面的书籍标题:%s", bookTitle);
  });

  console.log(result);
  await browser.close();
})();

方法2:批量暴露多个util方法

如果你需要用到util里的多个方法,可以写个小工具函数批量处理:

const puppeteer = require("puppeteer");
const util = require("util");
const path = "http://books.toscrape.com/";

// 批量暴露指定的util方法
async function exposeUtilMethods(page, methodNames) {
  for (const name of methodNames) {
    // 生成驼峰命名的全局函数名,比如util.inspect变成window.utilInspect
    const exposedName = `util${name.charAt(0).toUpperCase() + name.slice(1)}`;
    await page.exposeFunction(exposedName, (...args) => util[name](...args));
  }
}

(async () => {
  const browser = await puppeteer.launch({headless: false});
  const page = await browser.newPage();

  // 暴露format和inspect两个方法
  await exposeUtilMethods(page, ["format", "inspect"]);

  await page.goto(path, {waitUntil: "networkidle2"});

  const result = await page.evaluate(async () => {
    const firstBook = document.querySelector(".product_pod h3 a");
    // 使用暴露的utilInspect查看元素信息
    const elementInfo = utilInspect(firstBook);
    // 使用utilFormat格式化输出
    return utilFormat("第一本书的信息:%s", elementInfo);
  });

  console.log(result);
  await browser.close();
})();

方法3:复制util方法的实现到浏览器上下文

如果只是用到util里的简单工具函数(比如一些纯JS实现的方法),你可以直接把方法的代码复制到page.evaluate里,完全脱离Node端的依赖:

await page.evaluate(() => {
  // 直接在浏览器上下文实现util.format的核心逻辑
  function format(str, ...args) {
    return str.replace(/%[sdj%]/g, (match) => {
      if (match === "%%") return "%";
      const arg = args.shift();
      switch (match) {
        case "%s": return String(arg);
        case "%d": return Number(arg);
        case "%j": return JSON.stringify(arg);
        default: return match;
      }
    });
  }

  // 现在可以直接用这个format函数了
  console.log(format("Book: %s", document.querySelector("h1").textContent));
});

关键提醒

永远记住:page.evaluate的回调函数是在浏览器的V8环境里运行的,而你的Node.js代码是在Node.js的V8环境里运行的,这两个环境没有共享内存,只能通过可序列化的JSON数据或者exposeFunction这种桥接机制通信,直接传递Node.js模块对象是不可能的。

内容的提问来源于stack exchange,提问作者JdeMello

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 12:25:56