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

如何在Google Meet自动化中用Puppeteer处理并关闭‘Got it’弹窗?

解决Google Meet Puppeteer自动化中的"Got it"弹窗问题

问题描述

使用Puppeteer自动化Google Meet时,遇到带有"Got it"按钮的弹窗,会中断脚本流程,需要可靠的方式检测并关闭该弹窗,同时希望了解处理动态元素的更佳实践。

弹窗截图:
Google Meet "Got it"弹窗

用户原有代码及尝试过的ARIA选择器方法均未成功关闭弹窗。


解决方案

1. 可靠检测并关闭"Got it"弹窗的方法

方法一:基于文本内容的XPath定位

Google Meet的弹窗按钮文本通常比较稳定,使用XPath直接匹配文本内容可以避免ARIA标签可能的变动:

// 在进入会议后加入这段代码(比如点击Join now之后)
try {
  // 等待包含"Got it"文本的可见按钮
  const gotItButton = await page.waitForXPath('//button[contains(normalize-space(text()), "Got it")]', { 
    visible: true, 
    timeout: 8000 
  });
  await gotItButton.click();
  console.log("成功关闭'Got it'弹窗");
} catch (err) {
  console.log("未检测到'Got it'弹窗或无法关闭:", err);
}

方法二:使用waitForFunction自定义检测逻辑

如果按钮存在于动态加载的容器或Shadow DOM中,waitForFunction可以提供更灵活的检测逻辑:

try {
  // 等待按钮可见且可点击
  await page.waitForFunction(() => {
    const buttons = document.querySelectorAll('button');
    return Array.from(buttons).find(btn => 
      btn.textContent.trim() === 'Got it' && 
      btn.offsetParent !== null && // 确保元素可见
      btn.disabled === false // 确保元素可点击
    );
  }, { timeout: 8000 });
  
  // 点击按钮
  await page.click('button:has-text("Got it")');
  console.log("成功关闭'Got it'弹窗");
} catch (err) {
  console.log("未检测到'Got it'弹窗或无法关闭:", err);
}

2. 处理动态元素的更佳实践

  • 避免绝对XPath:绝对路径(如用户原有代码中的joinNowXPath)极易因页面结构变动失效,改用相对选择器:
    // 替换原有Join now按钮的点击逻辑
    try {
      await page.waitForSelector('button:has-text("Join now")', { visible: true });
      await page.click('button:has-text("Join now")');
      console.log("成功点击'Join now'按钮");
    } catch (err) {
      console.log("点击'Join now'按钮出错:", err);
    }
    
  • 替换固定延迟为等待事件:去掉waitForTimeout这类固定延迟,改用waitForSelector或waitForNavigation等待页面元素加载完成,适配不同网络环境:
    // 替换原有关闭摄像头的固定延迟,改为等待会议控件加载
    await page.waitForSelector('[aria-label="Turn off camera"]', { visible: true });
    // 再执行关闭摄像头操作
    await page.keyboard.down("ControlLeft");
    await page.keyboard.press("KeyE");
    await page.keyboard.up("ControlLeft");
    
  • 监听页面动态变化:通过page.on('domcontentloaded')或page.on('framenavigated')事件,处理动态插入的元素;对于Shadow DOM中的元素,可在page.evaluate中遍历Shadow Root查找:
    await page.evaluate(() => {
      // 遍历Shadow DOM查找元素
      const findInShadow = (el, selector) => {
        if (el.shadowRoot) {
          const found = el.shadowRoot.querySelector(selector);
          if (found) return found;
          el.shadowRoot.querySelectorAll('*').forEach(child => {
            const res = findInShadow(child, selector);
            if (res) return res;
          });
        }
        return null;
      };
      const gotItBtn = findInShadow(document.body, 'button:has-text("Got it")');
      if (gotItBtn) gotItBtn.click();
    });
    

修改后的完整代码示例

const puppeteer = require("puppeteer");
const { PuppeteerScreenRecorder } = require("puppeteer-screen-recorder");

const waitForTimeout = (milliseconds) => {
  return new Promise((resolve) => setTimeout(resolve, milliseconds));
};

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

  const page = await browser.newPage();

  // Listen for new pages and handle popups
  browser.on('targetcreated', async (target) => {
    if (target.type() === 'page') {
      const newPage = await target.page();
      const url = newPage.url();

      if (url.includes('https://meet.google.com/')) {
        console.log('Popup detected, closing it');
        await newPage.close();
      }
    }
  });

  const { width, height } = await page.evaluate(() => {
    return {
      width: window.screen.availWidth,
      height: window.screen.availHeight,
    };
  });
  await page.setViewport({ width, height });

  page.setDefaultNavigationTimeout(60000);

  await page.goto("https://accounts.google.com/");

  await page.waitForSelector('input[type="email"]');
  await page.type('input[type="email"]', "puppeteer@gmail.com");
  await page.click("#identifierNext");

  await page.waitForSelector('input[type="password"]', { visible: true });
  await page.type('input[type="password"]', "password@abc");
  await page.click("#passwordNext");

  const context = browser.defaultBrowserContext();
  await context.overridePermissions("https://meet.google.com/", [
    "microphone",
    "camera",
    "notifications",
  ]);

  await page.waitForNavigation();

  await waitForTimeout(2500);
  await page.goto("https://meet.google.com/");
  await page.waitForSelector('input[type="text"]');
  await page.click('input[type="text"]');
  await waitForTimeout(1000);
  await page.keyboard.type(`abc-kpxu-nrq`, { delay: 200 });// meeting code.
  await waitForTimeout(800);
  await page.keyboard.press("Enter");
  await page.waitForNavigation();

  // 等待会议控件加载,替代固定延迟
  await page.waitForSelector('[aria-label="Turn off camera"]', { visible: true, timeout: 10000 });
  
  // turn off cam using Ctrl+E
  await page.keyboard.down("ControlLeft");
  await page.keyboard.press("KeyE");
  await page.keyboard.up("ControlLeft");
  await waitForTimeout(1000);

  // turn off mic using Ctrl+D
  await page.keyboard.down("ControlLeft");
  await page.keyboard.press("KeyD");
  await page.keyboard.up("ControlLeft");
  await waitForTimeout(1000);

  // 优化Join now按钮点击逻辑
  try {
    await page.waitForSelector('button:has-text("Join now")', { visible: true, timeout: 10000 });
    await page.click('button:has-text("Join now")');
    console.log("成功进入会议");
  } catch (err) {
    console.log("Error while trying to click 'Join now' button: ", err);
  }

  // 处理Got it弹窗
  try {
    const gotItButton = await page.waitForXPath('//button[contains(normalize-space(text()), "Got it")]', { 
      visible: true, 
      timeout: 8000 
    });
    await gotItButton.click();
    console.log("成功关闭'Got it'弹窗");
  } catch (err) {
    console.log("未检测到'Got it'弹窗或无法关闭:", err);
  }

  const recorder = new PuppeteerScreenRecorder(page, { fps: 60 });
  await recorder.start(`puppeteerRecording.mp4`);

  setTimeout(async () => {
    await recorder.stop();
    await browser.close();
  }, 30000);
})();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 16:39:57