Puppeteer 确认

9
我正在学习 Puppeteer。我已经成功地编写了一个登录页面和一些导航的脚本,然后我让它点击了一个按钮。该页面弹出了一个 window.confirm 窗口,我希望我的脚本可以接受这个窗口以继续下一步,但我无法弄清楚如何实现。
有人能指点一下吗?

在puppeteer中有一个选项可以模拟键盘按键,我觉得关闭确认对话框就像按回车键一样简单。所以也许可以这样做 -> page.keyboard.press(String.fromCharCode(13)); - Keith
4个回答

18

刚刚在这里进行了一个简单的测试,当确认对话框弹出时,只需按下回车键即可关闭对话框。

因此,在 Puppeteer 中我们可以做到这一点。我制作了一个快速网页,其中包含一个确认框,...

例如:

<div>Before confirm</div>
<script>
  window.confirm("confirm");
  document.write("<div>After Confirm</div>");
</script>

现在是我们的Puppeteer脚本。

await delay(1000);
await page.keyboard.press(String.fromCharCode(13));  
await page.screenshot({path: 'screenshot.png'});
await browser.close();

按照以上步骤进行操作,我的屏幕截图如下:

Before confirm
After Confirm

如果按下确认对话框,这正是我们所期望的内容...delay只是一个简单的基于Promise的setTimeout函数,因此我们有机会等待确认对话框的出现。

如果您当前没有延迟Promise函数,则可以使用以下函数。

const delay = (ms) =>
  new Promise((resolve) => setTimeout(resolve, ms));

更新:不幸的是,对话框不能可靠地响应按键。但是,Puppeteer确实有一个我们可以附加到的对话框事件。

UPDATE: 很抱歉,对话框不能可靠地响应按键。但是,Puppeteer确实有一个我们可以附加到的对话框事件。

page.on("dialog", (dialog) => {
  console.log("dialog");
  dialog.accept();
});

您甚至可以解除,查看发送了什么消息等信息。更多信息请参见:https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#class-dialog


只是确认一下,我使用了您上面发布的示例,没有做任何更改,结果与我上面写的一样。我什么也没得到。Google Chrome 65.0.3325.181(官方版本)(64位)我需要做些什么来设置我的环境吗? - Michael Bierman
实际上,我不熟悉 Promise,所以我写了这个: await page.waitFor(1000);我确认这确实会引入一个暂停。问题不在于缺少延迟。返回值只是没有按预期执行或没有触发。然而,我不明白为什么会这样。 - Michael Bierman
谢谢,Keith。我一定还做错了什么。我尝试了你的示例,但它对我不起作用。由于评论在这里有限,我在这里设置了它。也许你可以告诉我我做错了什么。https://codepen.io/mbierman/pen/KoLpKe?editors=1111 - Michael Bierman
是的,这很奇怪!!!我总算找到了正确的处理方式。我会更新上面的片段。 - Keith
我花了一些时间学习,发现page.on("dialog" ...)代码必须放在触发对话框的任何代码之前。实际上,我不得不直接阅读puppeteer文档才能了解这一点。如果可能的话,如果将此与page.on("dialog" ...)代码一起展示,可能会帮助其他用户。或者只是我自己的问题。无论如何,谢谢! - Vladimir Brasil
显示剩余9条评论

4
确认提示由全局函数confirm(<string>)触发,该函数位于window.confirm。该函数会冻结脚本的执行,直到给出响应,然后将其返回给调用者。如果用户接受提示,则返回值将为true
由于我们正在网页中使用自定义浏览器会话,因此您可以使用任何内容覆盖全局变量。
因此,在运行触发确认窗口的操作之前,请运行以下内容。
await page.evaluate(`window.confirm = () => true`)

当页面代码调用 confirm() 时,它将立即获得一个 true 的响应,而不需要显示任何提示信息。


1
谢谢!我现在没有那个调制解调器,所以我不再维护相关的脚本了,但这是很好知道的。 - Michael Bierman
救了我的命!谢谢你! - Moshe

2
感谢,Keith!现在它像魔法一样工作了。如果任何人感兴趣,我已经发布了它在这里。 https://gist.github.com/mbierman/5b3e671fa4e848eec899ff486d0cdc26
#!/usr/bin/env node

/**
 * @name Reboot Arris modem. 
 *
 * @desc Puppeteer script for rebooting an Arris modem. 
 * since the specific navigation for your modem will vary, this 
 * is more of an example and isn't guaranteed to work for your particular
 * modem. 
 * Many thanks to https://stackoverflow.com/users/6870228/keith for his help!
 *
 */

const puppeteer = require('puppeteer')
const screenshot = 'arris.png';

/* Enter your user name and password here between the 's */
const USER = '';
const PASS = '';

    const delay = (ms) =>
    new Promise((resolve) => setTimeout(resolve, ms));

(async () => {

    const browser = await puppeteer.launch({headless: true})
    const page = await browser.newPage()

        console.log("Login...");
    await page.goto('http://192.168.0.1/login.asp');
    await page.type('#id_username', USER, { delay: 10 });
    await page.type('input[type="password"]', PASS, { delay: 10 });
    await page.click('[value="Login"]');
        console.log("Going home...");
    await page.goto('http://192.168.0.1/home.asp');
    await page.click('#alertExitButton');
        console.log("Config...");
    await page.goto('http://192.168.0.1/RgConfiguration.asp');
    console.log('Submit request...');
    page.click('input[type="submit"]');
    console.log('Pause...');

    await page.on("dialog", (dialog) => {
    console.log("Dialog is up...");
        delay(1000);
    console.log("Accepted...");
    dialog.accept();
        delay(1000);
    });

        await delay(3000);
        console.log("Exiting.");
    browser.close();
    process.exit(1);
})()

0

我们正在构建对象进行传递,所以有点不同,但我想分享一下。

我们为操作创建一个对象:

type: "operation",
name: "Touch Delete button from tracks-hero-tmp",
description: "Click and confirm delete and verify track cluster is 1 less",
actions: [
  { method: 'waitForSelector', value: '[tg-name=track_hero_delete_btn]' },
  { method: 'focus', value: '[tg-name=track_hero_delete_btn]' },
  { method: 'click', value: '[tg-name=track_hero_delete_btn]', accept_dialog: 'false' },
  { method: 'screenshot' }
],

然后将“accept_dialog”设置为布尔值,传递到异步函数中,并像这样设置对话框响应:

  if (accept_dialog) {
    await dialog.accept();
  } else {
    await dialog.dismiss();
  }

希望这能对某些人有所帮助。 :)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接