如何判断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
相关产品推荐
相关产品推荐

