【问题标题】:Puppeteer wait page load after form submitPuppeteer 表单提交后等待页面加载
【发布时间】:2022-04-02 09:29:15
【问题描述】:

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

【问题讨论】:

    标签: javascript puppeteer


    【解决方案1】:

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

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

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

    【讨论】:

      【解决方案2】:
      await page.waitForNavigation();
      

      【讨论】:

      • 这和await Promise.all([page.click..., page.waitForNavigation...]);有什么区别?
      • @NathanGoings 这里只有一个要解决的承诺,而 promise.all 将解决多个承诺(不一定按顺序)
      【解决方案3】:

      根据Official Documentation,你应该使用:

      page.waitForNavigation(选项)

      • options Object> 可能具有以下属性的导航参数:
        • timeout number> 最大导航时间,以毫秒为单位,默认为 30 秒,通过 0 禁用超时。可以使用page.setDefaultNavigationTimeout(timeout) 方法更改默认值。
        • waitUntil string|Arraystring>> 何时认为导航成功,默认为load。给定一个事件字符串数组,在所有事件都被触发后,导航被认为是成功的。事件可以是:
          • load - 考虑在load 事件触发时完成导航。
          • domcontentloaded - 考虑在DOMContentLoaded 事件触发时完成导航。
          • networkidle0 - 在至少 500 毫秒内没有超过 0 个网络连接时考虑完成导航。
          • networkidle2 - 在至少 500 毫秒内没有超过 2 个网络连接时考虑完成导航。
      • 返回:Promise> Promise 解析为主要资源响应。在多个重定向的情况下,导航将使用最后一个重定向的响应进行解析。如果由于 History API 的使用而导航到不同的锚点或导航,导航将解析为 null

      可读性:

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

      await page.waitForNavigation();
      

      性能:

      但由于page.waitForNavigation()page.mainFrame().waitForNavigation() 的快捷方式,我们可以使用以下内容来进行较小的性能提升:

      await page._frameManager._mainFrame.waitForNavigation();
      

      【讨论】:

      • 我正在尝试等待弹出窗口中的图像加载。可以暂停10秒吗?这些价值观都不适合我。
      • 性能提示是一种过早的优化,对实际性能没有任何实际意义。另外,在升级 puppeteer 后它更有可能崩溃,因为它使用的是内部 API
      【解决方案4】:

      有时即使使用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'})])
      

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

      【讨论】:

      • 我的重定向持续了很长时间,以至于只有 networkidle0 正常工作。
      • 一年多后我回来说,networkidle0 可能会神秘地失败(心跳、webpack hmr 等)在我当前的脚本中,我正在使用 page.waitForSelector
      【解决方案5】:

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

      (node:14531) UnhandledPromiseRejectionWarning: TimeoutError: 超过导航超时:超过 30000 毫秒 在 Promise.then (/home/user/nodejs/node_modules/puppeteer/lib/LifecycleWatcher.js:142:21) 在 -- 异步 -- 在框架。 (/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'});
      

      【讨论】:

        【解决方案6】:

        我建议将 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 取代吗?
        【解决方案7】:
        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) 时继续进行

        【讨论】:

        【解决方案8】:

        这对我有用:

        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')

        时,按钮都不存在

        解决方案是在Promise中绑定page.goto(URL)page.waitForNavigation({ waitUntil: 'networkidle0' })

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

        【讨论】:

        • 我来晚了,但这如何可靠地工作? page.goto 默认执行 waitUntil,然后您的第二个 waitForNavigation 将等待一个永远不会发生的导航,因为第一个响应?
        【解决方案9】:

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

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

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

        【讨论】:

          【解决方案10】:

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

          【讨论】:

            【解决方案11】:

            以上答案都没有解决我的问题。有时 waitForNavigation 只是超时。我使用 waitForFunction 提出了其他解决方案,检查文档是否处于就绪状态。

            await page.waitForFunction(() => document.readyState === "complete");
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2012-08-19
              • 1970-01-01
              • 2023-03-15
              • 2014-09-18
              • 2023-03-14
              • 1970-01-01
              • 2013-08-01
              • 1970-01-01
              相关资源
              最近更新 更多