You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何判断Puppeteer实例是否已存在并实现多脚本共享单浏览器

实现单个Puppeteer浏览器实例的复用与多脚本并发

要实现「存在则连接,不存在则创建」的共享浏览器逻辑,核心是利用Puppeteer的connect()方法,结合本地文件存储浏览器的WebSocket端点来让多个脚本共享连接信息。下面是具体的实现步骤和代码示例:

1. 核心思路

  • 当第一个脚本运行时,创建浏览器实例,并将其WebSocket端点写入本地文件(比如browser-endpoint.json)。
  • 后续脚本先读取这个文件里的端点,尝试用puppeteer.connect()连接已有的浏览器。
  • 如果连接失败(比如浏览器已关闭、文件不存在),则重新创建浏览器并更新端点文件。
  • 监听浏览器的disconnected事件,在浏览器关闭时删除端点文件,避免下次连接无效地址。

2. 通用浏览器复用函数

可以编写一个可复用的工具函数,让所有脚本都调用它来获取浏览器实例:

const puppeteer = require('puppeteer');
const fs = require('fs').promises;
const path = require('path');

const ENDPOINT_FILE = path.join(__dirname, 'browser-endpoint.json');

async function getSharedBrowser() {
  let browser;
  try {
    // 尝试读取已保存的端点
    const endpointData = await fs.readFile(ENDPOINT_FILE, 'utf8');
    const { wsEndpoint } = JSON.parse(endpointData);
    
    // 尝试连接已有浏览器
    browser = await puppeteer.connect({
      browserWSEndpoint: wsEndpoint,
      defaultViewport: null // 保持默认视口,可根据需求调整
    });

    // 验证连接是否有效(比如检查浏览器是否还在运行)
    await browser.version();
    console.log('已连接到现有浏览器实例');
  } catch (err) {
    // 连接失败,创建新的浏览器实例
    console.log('未找到有效浏览器实例,创建新实例');
    browser = await puppeteer.launch({
      headless: false, // 根据需求设置为true/false
      args: ['--no-sandbox', '--disable-setuid-sandbox'] // 可选,解决部分环境的权限问题
    });

    // 保存WebSocket端点到文件
    const wsEndpoint = browser.wsEndpoint();
    await fs.writeFile(ENDPOINT_FILE, JSON.stringify({ wsEndpoint }));

    // 监听浏览器断开事件,删除端点文件
    browser.on('disconnected', async () => {
      try {
        await fs.unlink(ENDPOINT_FILE);
        console.log('浏览器已关闭,端点文件已删除');
      } catch (err) {
        // 忽略文件不存在的错误
      }
    });
  }
  return browser;
}

module.exports = getSharedBrowser;

3. 在脚本中使用这个函数

每个需要运行的Puppeteer脚本,都可以这样调用:

const getSharedBrowser = require('./get-shared-browser');

async function runScriptTask() {
  const browser = await getSharedBrowser();
  // 创建新页面,每个脚本使用独立页面
  const page = await browser.newPage();
  
  try {
    // 这里写你的脚本逻辑,比如访问页面、操作DOM等
    await page.goto('https://example.com');
    const title = await page.title();
    console.log(`当前页面标题:${title}`);
    
    // 任务完成后可以关闭页面(但不要关闭浏览器,留着给其他脚本用)
    await page.close();
  } catch (err) {
    console.error('脚本执行出错:', err);
    await page.close();
  }
}

runScriptTask();

4. 注意事项

  • 并发启动脚本的冲突问题:如果多个脚本同时启动,都检测到没有端点文件,可能会重复创建浏览器。解决这个问题可以加一个简单的文件锁(比如创建临时锁文件,创建浏览器前检查锁是否存在),或者使用进程间通信工具来协调。
  • 资源清理:如果不再需要浏览器,记得手动调用browser.close(),否则它会一直运行。
  • 浏览器配置一致性:所有脚本使用的Puppeteer版本尽量保持一致,避免版本不兼容导致连接失败。
  • 无头模式:如果不需要可视化浏览器,可以把launch里的headless设为true(Puppeteer v19+后headless: 'new'是推荐的新无头模式)。

这样就能实现多个脚本共享同一个浏览器实例,各自在独立页面中并发运行的需求啦~

内容的提问来源于stack exchange,提问作者Nagarjun Prasad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 08:28:17