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

Puppeteer中MutationObserver内无法触发page.eval的问题排查

在Pokernow中通过MutationObserver监听下注变化时,正确调用Puppeteer逻辑的方法

核心问题原因

你遇到的问题本质是混淆了Puppeteer的两个隔离执行上下文:

  • Node.js上下文:脚本主逻辑、page对象、自定义打印函数都运行在这里
  • 浏览器上下文:page.evaluate注入的代码、MutationObserver的回调都运行在浏览器页面环境中

两个上下文无法直接跨域调用函数或方法——之前的写法试图在浏览器上下文里直接调用Node.js的page.evaluate,或是直接调用Node.js环境的打印函数,所以无法触发预期逻辑。

解决方案:两种可行实现方式

方式1:用window.postMessage传递数据到Node.js上下文

通过浏览器的消息机制把下注数据传递到Node.js环境,再执行打印逻辑,是跨上下文通信的常用方案。

  1. 在Node.js上下文监听页面消息:
// 监听浏览器发送的下注更新消息
page.on('message', (message) => {
  if (message.type === 'newBet') {
    console.log(`玩家 ${message.playerNum} 新下注金额:${message.amount}`);
  }
});
  1. 在浏览器上下文配置MutationObserver,检测变化后发送消息:
await page.evaluate(() => {
  // 替换为Pokernow实际的玩家DOM选择器
  const playerElements = document.querySelectorAll('.lobby-player');
  
  playerElements.forEach((playerEl, idx) => {
    const observer = new MutationObserver((mutations) => {
      mutations.forEach(mutation => {
        // 根据页面实际DOM变化类型调整判断条件
        if (mutation.type === 'childList' || mutation.target.classList.contains('bet-updated')) {
          // 替换为Pokernow实际的下注金额DOM选择器
          const betAmount = playerEl.querySelector('.player-bet-amount').textContent.trim();
          
          // 发送消息到Node.js上下文
          window.postMessage({
            type: 'newBet',
            playerNum: idx + 1,
            amount: betAmount
          });
        }
      });
    });

    // 配置观察选项,根据页面实际DOM更新逻辑调整
    observer.observe(playerEl, {
      childList: true,
      attributes: true,
      subtree: true,
      attributeFilter: ['class']
    });
  });
});

方式2:用page.exposeFunction暴露Node.js函数到浏览器上下文

把Node.js环境的打印逻辑暴露给浏览器,在MutationObserver回调里直接调用(注意是异步调用)。

  1. 先暴露Node.js函数到浏览器:
// 将打印函数暴露给浏览器上下文
await page.exposeFunction('logNewBet', (playerNum, amount) => {
  console.log(`玩家 ${playerNum} 新下注金额:${amount}`);
});
  1. 在浏览器上下文的MutationObserver回调中调用该函数:
await page.evaluate(async () => {
  const playerElements = document.querySelectorAll('.lobby-player');
  
  playerElements.forEach(async (playerEl, idx) => {
    const observer = new MutationObserver(async (mutations) => {
      for (const mutation of mutations) {
        if (mutation.type === 'childList' || mutation.target.classList.contains('bet-updated')) {
          const betAmount = playerEl.querySelector('.player-bet-amount').textContent.trim();
          // 调用暴露的Node.js函数,必须用await处理异步逻辑
          await window.logNewBet(idx + 1, betAmount);
        }
      }
    });

    observer.observe(playerEl, {
      childList: true,
      attributes: true,
      subtree: true,
      attributeFilter: ['class']
    });
  });
});

注意事项

  • 必须替换代码中的DOM选择器(如.lobby-player、.player-bet-amount)为Pokernow网站实际的元素选择器,可通过浏览器开发者工具查看获取。
  • MutationObserver的观察选项(如childList、attributes)需要根据Pokernow更新下注时的DOM变化类型调整,若仅为文本变化,需添加characterData: true。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 20:09:50