我可以打开多个Puppeteer浏览器吗?

时间:2019-04-06 22:40:50

标签: javascript node.js memory web-scraping puppeteer

我正在使用node-cron(它使您可以在节点程序中运行cron脚本)来运行操纵up的人。这些脚本有时会同时运行,这意味着将同时打开多个浏览器实例const browser = await puppeteer.launch()

这是不好的做法吗?如果是这样,还有另一种编写此代码的方法,它不会使它失败吗?

感谢您的帮助。

cron.schedule('*/15 * * * *', async () => {    
    const browser = await pupeteer.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox']});
    const page = await browser.newPage(); // Create new instance of puppet
    let today = moment();        
    logger.info(`Chrome Launched...`);

    try {
        await senatorBot(users, page, today.format("YYYY-DD-MM"));
    } catch(err) {
        logger.debug(JSON.stringify(err));
    }

    try {
        await senateCandidateBot(users, page, today.format("YYYY-DD-MM")); // This sequence matters, because agree statement will not be present...
    } catch(err) {
        logger.debug(JSON.stringify(err));
    }

    await page.close();
    await browser.close();
    logger.info(`Chrome Closed.`);

});

cron.schedule('*/15 17-19 * * 1-5', async () => {   

    logger.info(`Chrome Launched...`); 
    const browser = await pupeteer.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox']});
    const page = await browser.newPage(); // Create new instance of puppet
    let today = moment();

    try {
        await contractBot(users, page, today.format("MM-DD-YYYY"));
    } catch(err) {
        logger.debug(JSON.stringify(err));
    }

    await page.close();
    await browser.close();
    logger.info(`Chrome Closed.`);
});

2 个答案:

答案 0 :(得分:1)

确定,找到了一些代码以帮助您入门。该代码已绑定到我的自定义代码库中,但是我正在使用的功能可以轻松地由您自己的功能替换。

因此,首先,我编写一个简单的节点文件,该文件创建Chromium的实例,并保存对wsEndpoint的引用,以供以后用于连接。

文件:chromiumLauncher.js

const writeText = require("mylib/core.io.file/write-text");
const puppeteer = require("puppeteer");
const path = require("path");
const common = require("./common");

(async () => {
  const launch_options = {
    args: ['--disable-features=site-per-process'],
    headless: false,
    devtools: false,
    defaultViewport: {width: 1200, height: 1000},
    userDataDir: common.userDataDir
  };
  const browser = await puppeteer.launch(launch_options);
  const wsEndpoint = browser.wsEndpoint();
  await writeText(common.fnSettings, JSON.stringify({wsEndpoint}, null, "  "));
})();

在上面的common.js中,我只是存储一些简单的配置设置,您可以用自己的设置进行替换,它只是简单地存储一些路径,仅用于存储pupperteer放置数据文件的位置以及将{{ 1}}的值。 wsEndpoint只是一个简单的基于承诺的函数,用于编写文本文件,基本上是write-text,其编码设置为fs.writeFile

接下来,我们仅创建另一个名为utf-8的js文件,

connect

上面有几个自定义库函数int,但是应该很容易替换。 const puppeteer = require("puppeteer"); const cp = require('child_process'); const delay = require("mylib/promise/delay"); let browser = null; const readText = require("mylib/core.io.file/read-text"); const common = require("./common"); async function launch () { cp.spawn('node', ['chromiumLauncher.js'], { detached: true, shell: true, cwd: __dirname }); await delay(5000); //lets wait 5 seconds } async function getSettings() { try { const settingsTxt = await readText(common.fnSettings); return JSON.parse(settingsTxt); } catch (e) { if (e.code !== 'ENOENT') throw e; return null; } } async function connect () { if (browser) return browser; let settings = await getSettings(); if (!settings) { await launch(); settings = await getSettings(); } try { browser = await puppeteer.connect({browserWSEndpoint: settings.wsEndpoint}); } catch (e) { const err = e.error || e; if (err.code === "ECONNREFUSED") { console.log("con ref"); await launch(); settings = await getSettings(); browser = await puppeteer.connect({browserWSEndpoint: settings.wsEndpoint}); } } return browser; } module.exports = connect; ,与写文本正好相反,read-text只是基于承诺的简单延迟。

就是这样,使用..

delay

由于我们将Chromium分离开了,所以当进程关闭/连接时,它将保持打开状态。我在Chromium中打开了约7个进程,并与70个网页相关联,没有任何问题。需要注意的一件事是,因为我确实在分​​离的生成器中启动了铬,所以如果需要的话,还可以手动关闭铬。另一个选择是在某些流程管理器(例如PM2 https://www.npmjs.com/package/pm2

)中启动const connect = require("path-to/connect"); const browser = await connect(); const page = await browser.newPage();

答案 1 :(得分:1)

通常,只要您拥有足够强大的计算机,就可以并行打开两个浏览器。因此,答案完全取决于机器的资源。您是否有足够的内存和CPU来支持多个打开的Chrome浏览器?

检查您是否有足够的资源

如果您使用的是Linux,请打开htop之类的工具,以检查任务运行时处理了多少内存和CPU。达到CPU /内存限制时,应考虑按顺序运行任务(见下文)。

使用资源池

即使您有足够的资源,也可以使用库puppeteer-cluster(免责声明:我是作者)来处理并发处理。该库还将负责错误处理(如果浏览器崩溃会怎样?),并且可以在运行期间向您显示内存,CPU使用率和爬网统计信息。

代码示例

这是如何使用它的最小示例。

const { Cluster } = require('puppeteer-cluster');

async function task1({ page }) => { // your first task, page is provided to your task
    await page.goto('...');
    // ...
}

async function task2({ page }) => { // another task
    await page.goto('...');
    // ...
}

(async () => {
    const cluster = await Cluster.launch({
        concurrency: Cluster.CONCURRENCY_BROWSER, // spawn to parallel browsers
        maxConcurrency: 2, // how many tasks should be run concurrently
    });

    cron.schedule('...', () => {
        cluster.queue(task1);
    });

    cron.schedule('...', () => {
        cluster.queue(task2);
    });
})();

依序爬行

如果您的计算机没有资源来运行两个浏览器,则也可以一个接一个地运行任务,只需将maxConcurrency的值设置为1。然后,排队的任务将不会并行运行,而是顺序运行,因为只有一个开放资源。