Render部署Puppeteer服务遇Target.createTarget错误的解决办法
在Render平台部署带Puppeteer的Node.js服务器时遇到ProtocolError问题
我在Render平台部署配置了Puppeteer的Node.js服务器,已经编写了适配Puppeteer的Dockerfile,但部署后出现ProtocolError: Protocol error (Target.createTarget): Target closed错误,即使增大所有超时参数也无法解决。以下是相关代码、Dockerfile及错误日志,求解决方案:
相关代码
async function getResults(lnk) { const results = []; const timeFrames = [1, 5, 15]; const browser = await puppeteer.launch({ headless: 'new', args: [ "--disable-setuid-sandbox", "--no-sandbox", "--single-process", "--no-zygote", ], protocolTimeout: 240000,// 60秒 executablePath: process.env.NODE_ENV === "production" ? process.env.PUPPETEER_EXECUTABLE_PATH : puppeteer.executablePath(), }); const page = await browser.newPage(); // await page.setDefaultNavigationTimeout(0); for (const i of timeFrames) { const page = await browser.newPage(); const url = `${lnk}?timeFrame=${i * 60}`; console.log(`获取中: ${url}`); await page.goto(url, { waitUntil: ["domcontentloaded"],timeout: 100000 }); await page.waitForSelector("section.forecast-box-graph .title",{timeout: 10000}); // await page.waitForSelector('h1.main-title.js-main-title'); const status = await page.$eval( "section.forecast-box-graph .title", (el) => el.textContent ); const Bank_Name = await page.$eval("h1.main-title.js-main-title", (el) => el.textContent.trim() ); results.push(status); await page.close(); } await browser.close(); results.push(lnk.split("/").pop().split("-").join(" ")); return results; } async function scrape() { while(true){ for (const lnk of Link_Lst) { const results = await getResults(lnk); console.log("获取结果:",results); if(results.includes("Strong Sell")){ console.log("触发"); if (Sell_) { sendAlertToTG(`警报:银行 ${results.slice(-1)} - "强力卖出"`); Sell_ = false; } } if(results.includes("Strong Buy")){ if (Buy_) { sendAlertToTG(`警报:银行 ${results.slice(-1)} - "强力买入"`); Buy_ = false; } } } console.log("\n\n等待___10___秒"); waitBeforeNextIteration(10000); } } function waitBeforeNextIteration(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } scrape();
Dockerfile
FROM ghcr.io/puppeteer/puppeteer:20.1.2 ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \ PUPPETEER_EXECUTABLE_PATH=/usr/bin/google-chrome-stable WORKDIR /usr/src/app COPY package*.json ./ RUN npm ci COPY . . CMD [ "node", "index.js" ]
错误日志
[21:40:0508/181117.410689:ERROR:bus.cc(399)] 无法连接到总线:无法连接到套接字 /run/dbus/system_bus_socket: 没有该文件或目录 May 8 09:11:18 PM [21:46:0508/181118.422748:ERROR:bus.cc(399)] 无法连接到总线:无法连接到套接字 /run/dbus/system_bus_socket: 没有该文件或目录 May 8 09:11:18 PM [21:46:0508/181118.423699:ERROR:bus.cc(399)] 无法连接到总线:无法连接到套接字 /run/dbus/system_bus_socket: 没有该文件或目录 May 8 09:11:18 PM [21:40:0508/181118.455193:ERROR:bus.cc(399)] 无法连接到总线:无法解析服务器地址:未知地址类型(有效类型示例为 "tcp" 和 UNIX 下的 "unix") May 8 09:11:18 PM [21:40:0508/181118.455257:ERROR:bus.cc(399)] 无法连接到总线:无法解析服务器地址:未知地址类型(有效类型示例为 "tcp" 和 UNIX 下的 "unix") May 8 09:11:18 PM [21:21:0508/181118.604874:ERROR:system_network_context_manager.cc(765)] 单进程模式下无法使用 V8 代理解析器。 May 8 09:11:19 PM [21:40:0508/181119.040595:ERROR:bus.cc(399)] 无法连接到总线:无法解析服务器地址:未知地址类型(有效类型示例为 "tcp" 和 UNIX 下的 "unix") May 8 09:11:19 PM [21:40:0508/181119.041267:ERROR:bus.cc(399)] 无法连接到总线:无法解析服务器地址:未知地址类型(有效类型示例为 "tcp" 和 UNIX 下的 "unix") May 8 09:11:19 PM [21:21:0508/181119.042829:ERROR:system_network_context_manager.cc(765)] 单进程模式下无法使用 V8 代理解析器。 May 8 09:11:19 PM May 8 09:11:19 PM DevTools 监听 ws://127.0.0.1:36065/devtools/browser/534507b8-8bff-4967-907a-a39d4897f259 May 8 09:11:21 PM [21:93:0508/181121.222028:ERROR:bus.cc(399)] 无法连接到总线:无法连接到套接字 /run/dbus/system_bus_socket: 没有该文件或目录 May 8 09:11:21 PM [21:93:0508/181121.222132:ERROR:bus.cc(399)] 无法连接到总线:无法连接到套接字 /run/dbus/system_bus_socket: 没有该文件或目录 May 8 09:11:21 PM [21:93:0508/181121.222220:ERROR:bus.cc(399)] 无法连接到总线:无法连接到套接字 /run/dbus/system_bus_socket: 没有该文件或目录 May 8 09:11:21 PM [21:93:0508/181121.222285:ERROR:bus.cc(399)] 无法连接到总线:无法连接到套接字 /run/dbus/system_bus_socket: 没有该文件或目录 May 8 09:11:21 PM [21:93:0508/181121.222372:ERROR:bus.cc(399)] 无法连接到总线:无法连接到套接字 /run/dbus/system_bus_socket: 没有该文件或目录 May 8 09:11:22 PM [0508/181122.090203:ERROR:file_io_posix.cc(144)] 打开 /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq: 没有该文件或目录 (2) May 8 09:11:22 PM [0508/181122.090313:ERROR:file_io_posix.cc(144)] 打开 /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq: 没有该文件或目录 (2) May 8 09:11:22 PM /usr/src/app/node_modules/puppeteer-core/lib/cjs/puppeteer/common/Connection.js:61 May 8 09:11:22 PM _Callback_error.set(this, new Errors_js_1.ProtocolError()); May 8 09:11:22 PM ^ May 8 09:11:22 PM May 8 09:11:22 PM ProtocolError: Protocol error (Target.createTarget): Target closed May 8 09:11:22 PM at new Callback (/usr/src/app/node_modules/puppeteer-core/lib/cjs/puppeteer/common/Connection.js:61:35) May 8 09:11:22 PM at CallbackRegistry.create (/usr/src/app/node_modules/puppeteer-core/lib/cjs/puppeteer/common/Connection.js:106:26) May 8 09:11:22 PM at Connection._rawSend (/usr/src/app/node_modules/puppeteer-core/lib/cjs/puppeteer/common/Connection.js:216:26) May 8 09:11:22 PM at Connection.send (/usr/src/app/node_modules/puppeteer-core/lib/cjs/puppeteer/common/Connection.js:210:21) May 8 09:11:22 PM at CDPBrowser._createPageInContext (/usr/src/app/node_modules/puppeteer-core/lib/cjs/puppeteer/common/Browser.js:273:94) May 8 09:11:22 PM at CDPBrowserContext.newPage (/usr/src/app/node_modules/puppeteer-core/lib/cjs/puppeteer/common/Browser.js:541:78) May 8 09:11:22 PM at CDPBrowser.newPage (/usr/src/app/node_modules/puppeteer-core/lib/cjs/puppeteer/common/Browser.js:267:78) May 8 09:11:22 PM at getResults (/usr/src/app/index.js:79:32) May 8 09:11:22 PM at process.processTicksAndRejections (node:internal/process/task_queues:95:5) May 8 09:11:22 PM at async scrape (/usr/src/app/index.js:174:23) May 8 09:11:22 PM May 8 09:11:22 PM Node.js v18.16.0
解决方案
1. 移除单进程模式参数
错误日志明确提示单进程模式下无法使用 V8 代理解析器,当前启动参数里的--single-process和--no-zygote在Render容器环境中会导致Chrome启动异常或连接中断。修改Puppeteer启动配置:
const browser = await puppeteer.launch({ headless: 'new', args: [ "--disable-setuid-sandbox", "--no-sandbox", "--disable-dev-shm-usage", // 解决容器共享内存不足问题 "--disable-gpu", // 禁用GPU加速,容器环境无需 "--window-size=1920,1080" // 固定窗口大小,避免布局异常 ], protocolTimeout: 240000, executablePath: process.env.NODE_ENV === "production" ? process.env.PUPPETEER_EXECUTABLE_PATH : puppeteer.executablePath(), });
2. 修复代码中页面重复创建问题
getResults函数中先创建了一个未使用的page,循环内又重复创建同名变量,虽不直接引发错误,但会浪费资源。可改为循环复用单个页面,或删除多余创建:
async function getResults(lnk) { const results = []; const timeFrames = [1, 5, 15]; const browser = await puppeteer.launch({/* 修改后的配置 */}); // 删除多余的页面创建:const page = await browser.newPage(); for (const i of timeFrames) { const page = await browser.newPage(); const url = `${lnk}?timeFrame=${i * 60}`; console.log(`获取中: ${url}`); await page.goto(url, { waitUntil: "networkidle2", timeout: 100000 }); // 改用networkidle2等待页面加载完成 await page.waitForSelector("section.forecast-box-graph .title", { timeout: 30000 }); // 延长超时时间 const status = await page.$eval( "section.forecast-box-graph .title", (el) => el.textContent ); const Bank_Name = await page.$eval("h1.main-title.js-main-title", (el) => el.textContent.trim() ); results.push(status); await page.close(); } await browser.close(); results.push(lnk.split("/").pop().split("-").join(" ")); return results; }
3. 调整Dockerfile用户权限
Render容器环境默认可能禁止root用户运行Chrome,修改Dockerfile切换到非root用户:
FROM ghcr.io/puppeteer/puppeteer:20.1.2 ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \ PUPPETEER_EXECUTABLE_PATH=/usr/bin/google-chrome-stable WORKDIR /usr/src/app COPY package*.json ./ RUN npm ci COPY . . # 切换到puppeteer用户运行 USER puppeteer CMD [ "node", "index.js" ]
4. 增加错误捕获机制
添加try-catch块避免单个链接错误导致整个循环崩溃,同时输出详细错误信息:
async function getResults(lnk) { const results = []; const timeFrames = [1, 5, 15]; let browser; try { browser = await puppeteer.launch({/* 修改后的配置 */}); for (const i of timeFrames) { let page; try { page = await browser.newPage(); const url = `${lnk}?timeFrame=${i * 60}`; console.log(`获取中: ${url}`); await page.goto(url, { waitUntil: "networkidle2", timeout: 100000 }); await page.waitForSelector("section.forecast-box-graph .title", { timeout: 30000 }); const status = await page.$eval( "section.forecast-box-graph .title", (el) => el.textContent ); const Bank_Name = await page.$eval("h1.main-title.js-main-title", (el) => el.textContent.trim() ); results.push(status); } catch (pageErr) { console.error(`处理链接 ${lnk} 时间帧 ${i} 时出错:`, pageErr); results.push(`获取失败: ${pageErr.message}`); } finally { if (page) await page.close(); } } } catch (browserErr) { console.error(`启动浏览器处理链接 ${lnk} 时出错:`, browserErr); } finally { if (browser) await browser.close(); } results.push(lnk.split("/").pop().split("-").join(" ")); return results; }
内容的提问来源于stack exchange,提问作者hobik
相关产品推荐
相关产品推荐

