表单提交后,Puppeteer等待页面加载

时间:2017-10-26 07:43:25

标签: javascript puppeteer

我使用以下代码提交表单,我希望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等待页面加载?

10 个答案:

答案 0 :(得分:31)

您可以异步等待导航,以避免在重定向上获得null

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

如果page.click已触发导航,这将对您有所帮助。

答案 1 :(得分:25)

await page.waitForNavigation();

答案 2 :(得分:12)

根据Official Documentation,您应该使用:

  

page.waitForNavigation(选项)

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

可读性:

您可以使用page.waitForNavigation()等待页面导航:

await page.waitForNavigation();

性能:

但是,由于page.waitForNavigation()page.mainFrame().waitForNavigation()的快捷方式,因此我们可以使用以下内容来改善性能:

await page._frameManager._mainFrame.waitForNavigation();

答案 3 :(得分:0)

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))进一步进行操作

答案 4 :(得分:0)

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

  

(节点:14531)UnhandledPromiseRejectionWarning:TimeoutError:   超过导航超时:超过30000ms       然后在Promise.then(/home/user/nodejs/node_modules/puppeteer/lib/LifecycleWatcher.js:142:21)       在-ASYNC-       在帧。 (/家庭/用户/nodejs/node_modules/puppeteer/lib/helper.js:111:15)       在Page.waitForNavigation(/home/user/nodejs/node_modules/puppeteer/lib/Page.js:649:49)       在Page。 (/家庭/用户/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'});

答案 5 :(得分:0)

有时甚至使用await page.waitForNavigation()仍会产生Error: Execution context was destroyed, most likely because of a navigation.

就我而言,这是因为页面被多次重定向。 API表示默认的waitUntil选项是Load,这需要我等待每次重定向的导航(3次)。在我的情况下,仅将page.waitForNavigation的单个实例与waitUntil选项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 issue-在我的情况下,可以使用page.waitForXPath()

答案 6 :(得分:0)

我建议将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")

答案 7 :(得分:0)

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

答案 8 :(得分: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');

答案 9 :(得分:0)

如果提交表单会打开其他页面,那么您可能只想等待该页面中的选择器。我经常在使用 page.waitForNavigation() 时遇到问题,因为它的选项并不能真正确保我们有效地导航到另一个页面。

// login page
page.click("#login");
// homepage, after login
page.waitForSelector("#home", {visible: true}); // page.waitForXpath()

当然,您可以增加选择器的等待时间。