如何在 Puppeteer 中循环使用 page.on("dialog" ?

问题描述 投票:0回答:1

正如Puppeteer文档中所述,“dialog”事件的基本用法如下:

page.on('dialog', async (dialog) => {
  await dialog.dismiss() 
  // or await dialog.accept()
 })

我想循环浏览 URL 列表,每个 URL 都会触发一个确认对话框。 但我想根据页面内容接受或关闭对话框。

我想知道是否可以?

当我在循环中使用它时,出现错误:“无法关闭已处理的对话框!”

for (let url in urls) {
  if (condition) {
    page.on("dialog", async (dialog) => {
      await dialog.accept();
    });
  } else {
    page.on("dialog", async (dialog) => {
      await dialog.dismiss();
    });
  }
}

我在每个循环上添加一个侦听器,所以我收到错误。

但是当我将“对话框”侦听器移出循环时,我收到“对话框未定义”错误。

 page.on("dialog", async (dialog) => {

    for (let url in urls) {
      if (condition) {
        await dialog.accept();
      } else {
        await dialog.dismiss();
      }
    }
});

我尝试制作自定义事件侦听器。

await page.exposeFunction("test", async (e) => {
  // But I don't know how to dismiss or accept the confirm dialog here.
});

await page.evaluate(() => {
  window.addEventListener("confirm", window.test());
});

这种方法的问题是我无法访问负责处理确认对话框返回的

handleJavaScriptDialog
https://pub.dev/documentation/puppeteer/latest/puppeteer/Dialog/dismiss.html

到目前为止,我认为唯一的解决方案是模拟按 Enter 键来接受确认对话框,或者当我想关闭确认对话框时转到下一页。

是否有任何解决方案可以在像这样的 Puppeteer 循环中使用对话框事件?

======

更新

======

//@ggorlen 的示例

for (let url in urls) {
  await page.goto(url);

  const dialogDismissed = new Promise((resolve, reject) => {
    const handler = async (dialog) => {
      await dialog.dismiss();
      resolve(dialog.message());
    };
    page.on("dialog", handler);
  });

  const dialogAccepted = new Promise((resolve, reject) => {
    const handler = async (dialog) => {
      await dialog.accept();
      resolve(dialog.message());
    };
    page.on("dialog", handler);
  });

  await page.evaluate(() => window.confirm("Yes or No?"));

  if (condition) {
    //want to accept
    //how to handle the dialog promise here?
  } else {
    //want to dismiss
    //how to handle the dialog promise here?
  }
}

======

更新2

======

//基于@ggorlen的回答,但不承诺处理程序

const puppeteer = require("puppeteer");

let browser;
(async () => {
  const html = `<html><body><script>
    document.write(confirm("yes or no?") ? "confirmed" : "rejected");
  </script></body></html>`;
  browser = await puppeteer.launch({
    headless: true,
  });
  const [page] = await browser.pages();
  const urls = ["just", "a", "demo", "replace", "this"];

  for (const url of urls) {
    const someCondition = Math.random() < 0.5; // for example

    //This bloc is in question.
    //Is there a need to promisify?
    page.once("dialog", async (dialog) => {
      console.log(dialog.message());
      await (someCondition ? dialog.accept() : dialog.dismiss());
    });

    //await page.goto(url, {waitUntil: "networkidle0"});
    await page.setContent(html);
    console.log(await page.$eval("body", (el) => el.innerText));
  }
})()
  .catch((err) => console.error(err))
  .finally(() => browser?.close());
node.js loops events dialog puppeteer
1个回答
0
投票

这个答案是 Puppeteer 没有拾取对话框的变体。对该答案的快速总结:

.on
处理程序可以被承诺,以便轻松地将等待它们集成到控制流中,而无需混乱的回调。 OP 代码中似乎丢失的一个重要细微差别是,如果您只等待一次,请使用
.once
而不是
.on
,或者使用
.off
删除侦听器。解决后,监听器就变得陈旧了。

在这种情况下,假设您有一堆显示确认对话框的页面 URL(或者您注入自己的确认对话框),并且对于每个 URL,您希望为该对话框添加一个处理程序,以允许您接受或关闭它基于一个条件。您可能还想从对话框中收集消息,如下所示。

这是一个简单的例子:

const puppeteer = require("puppeteer"); // ^21.4.1

const html = `<html><body><script>
  document.write(confirm("yes or no?") ? "confirmed" : "rejected");
</script></body></html>`;

let browser;
(async () => {
  browser = await puppeteer.launch({headless: true});
  const [page] = await browser.pages();
  const urls = ["just", "a", "demo", "replace", "this"];

  for (const url of urls) {
    const someCondition = Math.random() < 0.5; // for example

    const dialogHandled = new Promise((resolve, reject) => {
      const handler = async dialog => {
        await (someCondition ? dialog.accept() : dialog.dismiss());
        resolve(dialog.message());
      };
      page.once("dialog", handler);
    });

    //await page.goto(url, {waitUntil: "networkidle0"});
    await page.setContent(html); // for demonstration
    const msg = await dialogHandled;
    console.log(msg, await page.$eval("body", el => el.innerText));
  }
})()
  .catch(err => console.error(err))
  .finally(() => browser?.close());

示例运行类似于:

yes or no? confirmed
yes or no? confirmed
yes or no? confirmed
yes or no? rejected
yes or no? rejected
© www.soinside.com 2019 - 2024. All rights reserved.