开发者问题收集

保持相同的 Puppeteer 页面打开 nodeJS

2019-09-22
8315

我正在开发一个 API,围绕在 Puppeteer 中打开的页面上运行一些 JS,但我不想一直打开/关闭并等待页面加载,因为这是一个内容繁重的页面。

是否可以在节点脚本上运行 forever start 来启动页面并使其永远保持打开状态并然后在需要在此页面上运行某些 javascript 时调用单独的节点脚本?

我尝试了以下操作,但似乎页面没有保持打开状态:

keepopen.js

'use strict';
const puppeteer = require('puppeteer');

(async() => {
    const start = +new Date();
    const browser = await puppeteer.launch({args: ['--no-sandbox']});
    const page = await browser.newPage();
    await page.goto('https://www.bigwebsite.com/', {"waitUntil" : "networkidle0"});
    const end =  +new Date();
    console.log(end - start);
    //await browser.close();
})();

runjs.js

'use strict';

const puppeteer = require('puppeteer');

(async() => {
    const start = +new Date();
    const browser = await puppeteer.launch({args: ['--no-sandbox']});
    const page = await browser.targets()[browser.targets().length-1].page();
    const hash = await page.evaluate(() => {
        return runFunction();
    });
    const end =  +new Date();
    console.log(hash);
    console.log(end - start);
    //await browser.close();
})();

我运行以下操作: forever start keepopen.js 然后运行 ​​ runjs.js 但出现错误:

(node:1642) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'evaluate' of null
2个回答

无法在两个 Node.js 脚本之间共享资源。您需要一个保持浏览器打开的服务器。

代码示例

下面是一个示例,使用库 express 启动服务器。调用 /start-browser 会启动浏览器并将浏览器和页面对象存储在当前函数之外。这样,第二个函数(在访问 /run 时调用)可以使用 page 对象在其中运行代码。

const express = require('express');
const app = express();

let browser, page;

app.get('/start-browser', async function (req, res) {
    browser = await puppeteer.launch({args: ['--no-sandbox']});
    page = await browser.newPage();
    res.end('Browser started');
});

app.get('/run', async function (req, res) {
    await page.evaluate(() => {
        // ....
    });
    res.end('Done.'); // You could also return results here
});

app.listen(3000);

请记住,这是一个帮助您入门的最小示例。在现实世界中,您需要捕获错误,并且可能还需要不时重新启动浏览器。

Thomas Dondorf
2019-09-22

您可以使用节点运行 http 服务器,其中 puppeteer page 对象在启动时创建一次,然后通过将该代码放入(所谓的)“路由”函数(只是一个服务于 Web 请求的函数)中来启动当前脚本。您创建的 http 服务器。

只要 page 对象是在包含您的代码的路由函数范围之外创建的,您的路由函数将在众多 Web 请求之间保持对同一 page 对象的访问。

您将能够反复重用同一个 page 对象,而不必像当前一样在每次调用时重新加载它。但是,您需要一个服务来在请求/调用之间保留 page 对象。

您可以创建自己的 http 服务器(使用 node 的内置 http 包),也可以使用 express (除了 express 之外,还有许多其他基于 http 的包可供使用)。

Lonnie Best
2019-09-22