提交表单后,操纵up的页面等待


76

我使用以下代码提交表单,我希望Puppeteer在表单提交后等待页面加载。

await page.click("button[type=submit]");

//how to wait until the new page loads before taking screenshot?
// i don't want this:
// await page.waitFor(1*1000);  //← unwanted workaround
await page.screenshot({path: 'example.png'});

如何使用puppeteer等待页面加载?

Answers:


77

您可以异步等待导航,以避免null进行重定向,

await Promise.all([
      page.click("button[type=submit]"),
      page.waitForNavigation({ waitUntil: 'networkidle0' }),
]);

如果page.click已经触发导航,这将为您提供帮助。


4
networkidle现在应该设置为networkidle2 github.com/GoogleChrome/puppeteer/blob/master/docs/…–
ryannjohnson

@ryannjohnson我在文档中看不到提到networkidle2的必要之处吗?自您发表评论以来,文档可能已更改?
Hylle

我的评论是关于networkidle的,他为我提供了networkidle2的帮助。不必等待networkidle0或networkidle2。
阿布·塔赫女士

48
await page.waitForNavigation();

5
和之间有什么区别await Promise.all([page.click..., page.waitForNavigation...]);
内森·高斯

32

根据官方文档,您应该使用:

page.waitForNavigation(选项)

  • options<对象>导航参数,可能具有以下属性:
    • timeout< number >最大导航时间(以毫秒为单位),默认为30秒,传递0以禁用超时。可以使用page.setDefaultNavigationTimeout(timeout)更改默认值。方法。
    • waitUntil<字符串| Array < string >>当认为导航成功时,默认为load。给定事件字符串数组,所有事件触发后,导航被认为是成功的。事件可以是:
      • load-当load事件触发时,请考虑完成导航。
      • domcontentloaded-当DOMContentLoaded事件触发时,请考虑完成导航。
      • networkidle0-当网络连接数不超过0至少500ms时,请考虑完成导航。
      • networkidle2-当至少两个500ms的网络连接不超过2个时,请考虑完成导航。
  • 返回:< Promise <[?Response] >> Promise,它解析为主要资源响应。如果是多次重定向,导航将以最后一次重定向的响应来解决。如果使用History API导航到其他锚点或导航,导航将以解析null

可读性:

您可以page.waitForNavigation()用来等待页面浏览:

await page.waitForNavigation();

性能:

但由于page.waitForNavigation()是的捷径page.mainFrame().waitForNavigation(),因此我们可以使用以下内容来进行较小的性能增强:

await page._frameManager._mainFrame.waitForNavigation();

1
我正在尝试等待弹出窗口中的图像加载。可以暂停10秒钟吗?这些价值观都不适合我。
chovy

8
性能提示是一个过早的优化,对实际性能没有任何实用性。加上它的更容易,因为它是使用内部API木偶升级后打破
Soufiane Ghzal

8

我知道回答这个问题有点晚了。对于那些在执行waitForNavigation时遇到异常的人可能会有所帮助。

(节点:14531)UnhandledPromiseRejectionWarning:超时错误:导航超时:在Promise处超过30000ms。然后(/home/user/nodejs/node_modules/puppeteer/lib/LifecycleWatcher.js:142:21)在-ASYNC-在框架处。(/home/user/nodejs/node_modules/puppeteer/lib/helper.js:111:15)位于Page.waitForNavigation(/home/user/nodejs/node_modules/puppeteer/lib/Page.js:649:49) 。(/home/user/nodejs/node_modules/puppeteer/lib/helper.js:112:23)位于/home/user/nodejs/user/puppeteer/example7.js:14:12

适用于我的正确代码如下。

await page.click('button[id=start]', {waitUntil: 'domcontentloaded'});

同样,如果您要转到新页面,则代码应类似于

await page.goto('here goes url', {waitUntil: 'domcontentloaded'});

1
谢谢。这真的很有帮助。我什至在官方网站上找不到正确的语法。
标记

8

有时即使使用await page.waitForNavigation()仍然会导致Error: Execution context was destroyed, most likely because of a navigation.

以我为例,这是因为该页面多次重定向。该API表示默认waitUntil选项Load-这种要求我等待导航每个重定向(3次)。

在我的情况下,仅使用page.waitForNavigationwithwaitUntil选项的单个实例networkidle2效果很好:

await button.click();

await page.waitForNavigation({waitUntil: 'networkidle2'});

最后,API建议使用Promise.All来防止竞争情况。 我不需要这个,但是为了完整性而提供

await Promise.all([button.click(), page.waitForNavigation({waitUntil:'networkidle2'})])

如果所有其他方法均失败,则可以page.waitForSelector按照Puppeteer github问题上的建议使用,或者在我的情况下,page.waitForXPath()


我进行的重定向持续了很长时间,只能networkidle0正常工作。
内森·高斯

5

我建议将page.to包装在包装器中,并等待所有内容加载

这是我的包装纸

loadUrl: async function (page, url) {
    try {
        await page.goto(url, {
            timeout: 20000,
            waitUntil: ['load', 'domcontentloaded', 'networkidle0', 'networkidle2']
        })
    } catch (error) {
        throw new Error("url " + url + " url not loaded -> " + error)
    }
}

现在您可以将其与

await loadUrl(page, "https://www.google.com")

是不是在等待中networkidle0被等待取代networkidle2
rinogo

2
await Promise.all([
      page.click(selectors.submit),
      page.waitForNavigation({ waitUntil: 'networkidle0' }),
]);

这将是使用的第一优先级,因为它等待所有网络完成,并假定在500毫秒内网络呼叫不超过0个时完成。

你也可以使用

await page.waitForNavigation({ waitUntil: 'Load' })

否则,您可以使用

await page.waitForResponse(response => response.ok())

此功能也可以在各个地方使用,因为它仅允许在所有呼叫都成功时(即,所有响应状态都正常时,即(200-299))进一步进行


waitUntil: 'load'。仅小写字母有效。REF:github.com/puppeteer/puppeteer/blob/master/docs/...
Thanwa章。

0

我遇到了一个场景,其中有经典的POST-303-GET并input[type=submit]涉及其中。似乎在这种情况下,click直到关联的表单提交和重定向之后,按钮的才会解析,因此解决方案是删除waitForNavigation,因为它是在重定向之后执行的,因此超时了。


0

这为我工作:

await Promise.all([
    page.goto(URL),
    page.waitForNavigation({ waitUntil: 'networkidle0' }),
]);
console.log('page loaded')

由于某种原因,我无法单击按钮(处理了一个事件,不是形式上的)

<button onclick="someFunction();" class="button button2">Submit</button>

问题在于该页面是在服务器端呈现的。因此,每当我等待输入字段时按钮都不存在await page.waitForSelector('button.button2')

解决的办法是结合page.goto(URL)page.waitForNavigation({ waitUntil: 'networkidle0' })Promise

await Promise.all([
    page.goto(URL),
    page.waitForNavigation({ waitUntil: 'networkidle0' }),
]);
console.log('page loaded')

await page.waitForSelector('button.button2')
console.log('button is here');
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.