【问题标题】:UnhandledPromiseRejectionWarning: Error: Page crashed! While using puppeteerUnhandledPromiseRejectionWarning:错误:页面崩溃!在使用 puppeteer 时
【发布时间】:2020-01-17 06:46:03
【问题描述】:

所以我使用了一个 while 循环,所以我的测试将在一个恒定循环中运行,直到我的后端崩溃。 我已经实现了 try and catch(error),所以任何前端崩溃,自动化都会刷新并继续运行

while(true){
try{
    await page.waitFor(selector)
    await page.click(selector)    
}
catch(error){
    console.log("FE crashed with\n\n" + error + "\n\nRefreshing page and continuing profile switching")
    await page.reload(page);
    continue;
}}

因此,实际上任何超时错误都会自动刷新页面并继续循环。 但我收到不同的崩溃错误

(node:6535) UnhandledPromiseRejectionWarning: Error: Page crashed!
at Page._onTargetCrashed (/home/raymond/node_modules/puppeteer/lib/Page.js:170:24)
at CDPSession.Page.client.on.event (/home/raymond/node_modules/puppeteer/lib/Page.js:125:56)
at CDPSession.emit (events.js:182:13)
at CDPSession._onMessage (/home/raymond/node_modules/puppeteer/lib/Connection.js:200:12)
at Connection._onMessage (/home/raymond/node_modules/puppeteer/lib/Connection.js:112:17)
at _tickCallback (internal/process/next_tick.js:43:7)
at listOnTimeout (timers.js:294:7)
at processTimers (timers.js:268:5)
(node:6535) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)

我该如何处理这个错误?如果我手动刷新页面一切正常。 谢谢

【问题讨论】:

  • 我看起来像你的 puppeteer “page” 在 “catch” 部分崩溃了,而且你里面没有另一个 “try...catch”。尝试处理此错误。有时 puppeteer 本身会崩溃、chromium 崩溃等……所以你也必须处理这些错误。例如,您可以关闭页面(或浏览器)并创建另一个页面(或浏览器)。
  • 好的,我可以试试这个,但是我怎么知道系统崩溃了,我的意思是我的try and catch没有工作,所以try and catch整个循环?
  • 我想尝试...catch 里面的catch,只是为了发出“await page.reload(page)”命令,因为我认为这是导致问题的原因。但是尝试...在浏览器创建中捕获 while() 会更好。
  • 我试过尝试捕获while循环并没有解决问题我会尝试你的建议
  • 你想要await page.reload();,将页面作为选项传递是没有意义的。你可能想看看reload docs and options

标签: javascript node.js mocha.js puppeteer


【解决方案1】:

根据官方文档,当页面崩溃时会发出“错误”事件,该事件可用于根据应用程序执行某些操作。

page.on('error', err => { /*custom logic to handle the crash*/ });

对于上述特定用例,您可以这样做:

let browser = await puppeteer.launch();
let page = await getNewPage(browser);

while(true){
        try{
            if (page.isClosed()) {
              page = await getNewPage(browser);
            }
            await page.waitFor(selector)
            await page.click(selector)    
        }
        catch(error){
            console.log("FE error with\n\n" + error + "\n\nRefreshing page and continuing profile switching")
            await page.reload();
            continue;
        }}


async function getNewPage(browser) {
    let page = await browser.newPage();
    page.on('error', err => {
        if (!page.isClosed()) {
            //Close page if not closed already
            page.close();
        }
    }
    return page;
}

参考:page.on('error')

【讨论】:

    【解决方案2】:

    您假设发生错误是因为页面导航失败。可能是这种情况,但也可能是一个不同的错误,如Protocol error。在这种情况下,您不能只重用page 对象,而是首先必须重新启动浏览器。

    前段时间,我crawled roughly 400k pages for testing purposes。我总共经历了 34 次 puppeteer 崩溃,其中一些意外错误导致整个浏览器崩溃。要强化您的代码以防止此类崩溃,您需要一种可靠的方法来重新启动浏览器。

    代码示例

    let browser = await puppeteer.launch(/* .. */);
    let page = await browser.newPage();
    
    while(true) {
        try {
            // your code that might crash
        } catch (err) {
            try {
                await page.reload(); // soft fix
            } catch (recoveringErr) {
                // unable to reload the page, hard fix
                try {
                    await browser.close();
                } catch (err) { // browser close was not necessary
                    // you might want to log this error
                }
                browser = await puppeteer.launch(/* .. */);
                page = await browser.newPage();
            }
        }
    }
    

    虽然这段代码在三个嵌套的 try..catch 块中看起来很可怕,但它可以很好地保持代码运行。

    首先,执行您的原始代码。如果发生最初的问题,则会尝试拨打page.reload 来解决问题。如果这有效,循环将继续运行。如果这不起作用,将重新启动浏览器。

    要重启浏览器,我建议先尝试关闭旧浏览器。虽然这可能会失败,但它会清除所有内存并正确处理浏览器对象。根据您的用例,您可能想要记录错误或干脆忽略它。处理完旧的浏览器对象后,可以重启浏览器,循环可能会继续。

    替代方案

    作为替代方案,您可以使用我的库puppeteer-cluster,它内置了错误处理功能。如果页面不再可用,该库会自动重新启动浏览器。此外,该库可以并行运行多个页面(当您尝试对我假设的服务器进行压力测试时)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-03-22
      • 1970-01-01
      • 2019-03-16
      • 2013-10-10
      • 1970-01-01
      • 1970-01-01
      • 2022-01-16
      • 1970-01-01
      相关资源
      最近更新 更多