Puppeteer:处理单击a [target =“ _ blank”]创建的页面的更简单方法;等待加载并包含超时

时间:2019-01-02 07:17:44

标签: javascript node.js puppeteer

概述

我正在寻找一种处理单击打开新页面的链接的简单方法(例如target =“ _ blank”定位标记)。

此处的句柄表示:

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

复制步骤

向我们介绍您的环境:

  • 木偶版本:^ 1.11.0
  • 平台/操作系统版本:64位,赢得10专业版
  • 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;

预期结果是什么?

一种处理新标签的简便且一致的方法

会发生什么?

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

使用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)
  

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

1 个答案:

答案 0 :(得分:3)

首先运行click函数,并删除promise内的“全局”,并声明promise外的浏览器为常量

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;