如何在Puppeteer中捕获新窗口弹窗的Alert消息?
解决Puppeteer捕获新窗口Alert消息的问题
核心问题分析
你的代码中dialog事件绑定时机过晚:在等待到popup页面后才绑定dialog事件,但此时Alert可能已经触发完毕,导致事件监听器无法捕获到消息。此外,popup.on("dialog")不需要用await修饰,事件绑定是同步操作。
修正方案
方案1:监听浏览器全局Dialog事件
由于新窗口的Alert属于浏览器全局的Dialog事件,直接在Browser实例上监听dialog事件可以确保不会错过任何弹窗,无论弹窗来自哪个页面。
修改后的代码:
const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch({ headless: false, slowMo: 50 }); const page = await browser.newPage(); await page.goto('http://www.rbmtest.com.co/AdminMenuMonWeb/pages/welcome/Login.jsp', { waitUntil: "networkidle0" }); try { // 提前监听浏览器全局的dialog事件 let dialogMsg = null; const dialogPromise = new Promise(resolve => { browser.once('dialog', async dialog => { dialogMsg = dialog.message(); console.log('捕获到Alert消息:', dialogMsg); await dialog.accept(); resolve(); }); }); // 监听新窗口弹出 const newPagePromise = new Promise(tab => page.once('popup', tab)); // 输入账号密码(错误示例) await page.type('#login', 'jhonsmith'); await page.type('#password', 'France5523*!'); // 点击提交按钮 await page.click('input[name="b1"]'); // 等待新窗口和dialog事件完成 const popup = await newPagePromise; await dialogPromise; // 根据是否捕获到错误消息处理逻辑 if (dialogMsg) { // 登录失败:写入数据库逻辑 console.log('登录失败,错误消息:', dialogMsg); } else { // 登录成功:等待页面元素验证后写入数据库 await popup.waitForXPath('//*[@id="as_cssmenu"]/ul/li[1]/a', { timeout: 5000 }); console.log('登录成功'); } await popup.close(); await page.close(); } catch (error) { console.log('执行错误:', error); await page?.close(); } await browser.close(); })();
方案2:提前绑定Popup页面的Dialog事件
如果需要仅针对新窗口监听Dialog,可以在等待Popup的同时,通过targetcreated事件提前获取页面实例并绑定事件,避免绑定时机过晚:
const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch({ headless: false, slowMo: 50 }); const page = await browser.newPage(); await page.goto('http://www.rbmtest.com.co/AdminMenuMonWeb/pages/welcome/Login.jsp', { waitUntil: "networkidle0" }); try { let dialogMsg = null; let popupPage = null; // 监听targetcreated事件,提前获取新页面并绑定dialog事件 const newPagePromise = new Promise(resolve => { browser.on('targetcreated', async target => { if (target.type() === 'page' && target.url() !== page.url()) { popupPage = await target.page(); // 立即绑定dialog事件 popupPage.once('dialog', async dialog => { dialogMsg = dialog.message(); console.log('捕获到Alert消息:', dialogMsg); await dialog.accept(); }); resolve(popupPage); } }); }); // 输入账号密码 await page.type('#login', 'jhonsmith'); await page.type('#password', 'France5523*!'); // 点击提交 await page.click('input[name="b1"]'); // 等待新页面加载 await newPagePromise; // 处理登录结果 if (dialogMsg) { console.log('登录失败'); // 写入数据库逻辑 } else { await popupPage.waitForXPath('//*[@id="as_cssmenu"]/ul/li[1]/a', { timeout: 5000 }); console.log('登录成功'); // 写入数据库逻辑 } await popupPage.close(); await page.close(); } catch (error) { console.log('执行错误:', error); await page?.close(); } await browser.close(); })();
关键注意事项
- 事件绑定时机:必须在触发弹窗的操作(点击提交按钮)之前,完成Dialog事件的监听绑定。
- Dialog事件的异步性:Dialog事件是异步触发的,需要用Promise等待事件完成后再进行后续逻辑判断。
- 避免重复监听:使用
once替代on监听事件,防止多次触发导致逻辑混乱。
内容的提问来源于stack exchange,提问作者Smith Brown
相关产品推荐
相关产品推荐

