Puppeteer:更简单的方法来处理点击 a[target="_blank"] 时创建的页面;等待加载并包括超时

Dhe*_*kar 5 javascript node.js puppeteer

概述

我正在寻找一种更简单的方法来处理点击打开新页面的链接(如 target="_blank" 锚标签)。

这里的句柄意味着:

  • 获取新的页面对象
  • 等待新标签加载(超时)

重现步骤

告诉我们您的环境:

  • 傀儡师版本:^1.11.0
  • 平台/操作系统版本:64位,win 10 pro
  • URL(如果适用):无
  • Node.js 版本:v10.15.0

我查看了相关问题:

https://github.com/GoogleChrome/puppeteer/issues/386 https://github.com/GoogleChrome/puppeteer/issues/3535 https://github.com/GoogleChrome/puppeteer/issues/978

哪些步骤将重现该问题?

我已经包含了下面的代码片段

我试图:

  1. 单击链接打开新选项卡时,获取新页面的对象。(链接是动态生成的,捕获href可能不是最优雅的方式)

  2. 等到新页面加载(超时)。如果您可以使用 page.waitForNavigation 保持一致性,我会很高兴

  3. 关闭选项卡并返回先前的选项卡以继续进一步操作

请包含重现问题的代码。

// as referenced here on #386 : https://github.com/GoogleChrome/puppeteer/issues/386#issuecomment-425109457
    const getNewPageWhenLoaded =  async () => {
        return new Promise(x =>
            global.browser.on('targetcreated', async target => {
                if (target.type() === 'page') {
                    const newPage = await target.page();
                    const newPagePromise = new Promise(y =>
                        newPage.once('domcontentloaded', () => y(newPage))
                    );
                    const isPageLoaded = await newPage.evaluate(
                        () => document.readyState
                    );
                    return isPageLoaded.match('complete|interactive')
                        ? x(newPage)
                        : x(newPagePromise);
                }
            })
        );
    };


const newPagePromise = getNewPageWhenLoaded();
await page.click('my-link'); // or just do await page.evaluate(() => window.open('https://www.example.com/'));
const newPage = await newPagePromise;
Run Code Online (Sandbox Code Playgroud)

预期的结果是什么?

处理新选项卡的更简单一致的方法

会发生什么?

开发人员必须编写看起来像管道(内部/低级)命令的内容。

使用 waitForTarget 可能会简化这一点,但我无法让谓词返回正确的类型。这是我的非功能性代码

private async getNewPageWhenLoaded() {
        const newTarget = await this._browser.waitForTarget(async (target) => {
            const newPage = await target.page();
            await newPage.waitForNavigation(this._optionsNavigation);
            // const newPagePromise = new Promise(() => newPage.once('load', () => x(newPage)));
            return await newPage.evaluate("true");
        });
        return await newTarget.page();
    }

// elsewhere in the code
            const newPagePromise = this.getNewPageWhenLoaded();
            await resultItem.element.click();
            const newPage = <Page>await newPagePromise;

//I get the following error
DevTools listening on ws://127.0.0.1:31984/devtools/browser/bf86648d-d52d-42d8-a392-629bf96211d4
(node:5564) UnhandledPromiseRejectionWarning: Error: Navigation failed because browser has disconnected!
    at CDPSession.LifecycleWatcher._eventListeners.helper.addEventListener (<path-to-my-project>\node_modules\puppeteer\lib\FrameManager.js:1181:107)
    at CDPSession.emit (events.js:182:13)
    at CDPSession._onClosed (<path-to-my-project>\node_modules\puppeteer\lib\Connection.js:231:10)
    at Connection._onMessage (<path-to-my-project>\node_modules\puppeteer\lib\Connection.js:103:19)
    at WebSocketTransport._ws.addEventListener.event (<path-to-my-project>\node_modules\puppeteer\lib\WebSocketTransport.js:41:24)
    at WebSocket.onMessage (<path-to-my-project>\node_modules\ws\lib\event-target.js:120:16)
    at WebSocket.emit (events.js:182:13)
    at Receiver.receiverOnMessage (<path-to-my-project>\node_modules\ws\lib\websocket.js:741:20)
    at Receiver.emit (events.js:182:13)
    at Receiver.dataMessage (<path-to-my-project>\node_modules\ws\lib\receiver.js:417:14)
  -- ASYNC --
    at Frame.<anonymous> (<path-to-my-project>\node_modules\puppeteer\lib\helper.js:144:27)
    at Page.waitForNavigation (<path-to-my-project>\node_modules\puppeteer\lib\Page.js:644:49)
    at Page.<anonymous> (<path-to-my-project>\node_modules\puppeteer\lib\helper.js:145:23)
    at newTarget._browser.waitForTarget (<path-to-my-project>\pageObjects\MyPage.js:104:27)
    at process._tickCallback (internal/process/next_tick.js:68:7)
(node:5564) 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: 1)
(node:5564) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
(node:5564) UnhandledPromiseRejectionWarning: TimeoutError: Navigation Timeout Exceeded: 300000ms exceeded
    at Promise.then (<path-to-my-project>\node_modules\puppeteer\lib\FrameManager.js:1276:21)
  -- ASYNC --
    at Frame.<anonymous> (<path-to-my-project>\node_modules\puppeteer\lib\helper.js:144:27)
    at Page.waitForNavigation (<path-to-my-project>\node_modules\puppeteer\lib\Page.js:644:49)
    at Page.<anonymous> (<path-to-my-project>\node_modules\puppeteer\lib\helper.js:145:23)
    at newTarget._browser.waitForTarget (<path-to-my-project>\pageObjects\MyPage.js:104:27)
    at process._tickCallback (internal/process/next_tick.js:68:7)
(node:5564) 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)
Run Code Online (Sandbox Code Playgroud)

注意:我在 github 上创建的问题:https : //github.com/GoogleChrome/puppeteer/issues/3718

Igg*_*ios 5

首先首先运行点击功能并删除承诺内的“全局”并在承诺外将浏览器声明为常量

const browser = await puppeteer.launch();
await page.click('my-link'); 
const getNewPageWhenLoaded =  async () => {
    return new Promise(x =>
        browser.on('targetcreated', async target => {
            if (target.type() === 'page') {
                const newPage = await target.page();
                const newPagePromise = new Promise(y =>
                    newPage.once('domcontentloaded', () => y(newPage))
                );
                const isPageLoaded = await newPage.evaluate(
                    () => document.readyState
                );
                return isPageLoaded.match('complete|interactive')
                    ? x(newPage)
                    : x(newPagePromise);
            }
        })
    );
};


const newPagePromise = getNewPageWhenLoaded();
const newPage = await newPagePromise;
Run Code Online (Sandbox Code Playgroud)