如何修复Puppeteer爬取电商新品时的spawn ENAMETOOLONG错误?
Error: spawn ENAMETOOLONG的问题 核心原因分析
ENAMETOOLONG错误本质是系统判定你传递给进程的命令行参数长度超出了限制。结合你的代码和运行场景,最可能的触发点是代理插件重复注册,其次是浏览器进程未彻底清理导致的参数累积。
具体解决思路
1. 修复代理插件重复注册的问题
看你的代码,每次调用getData函数都会执行puppeteer.use(pluginProxy),这会不断给Puppeteer实例重复添加同一个代理插件。每添加一次,启动浏览器时的命令行参数就会多一堆代理相关配置,运行数小时后参数长度就会突破系统限制,直接触发ENAMETOOLONG。
修改方法:把插件注册代码移到函数外部,只执行一次:
const puppeteer = require('puppeteer-extra'); const pluginProxy = require('puppeteer-extra-plugin-proxy'); // 仅注册一次代理插件,不要放在getData函数内部 puppeteer.use(pluginProxy({ port: 1050, credentials: { username: 'okQLjn', password: 'vYTNDiJ24D', } })); async function getData(urlNew, ...args, proxy) { // 动态设置当前请求的代理地址(插件支持动态切换) // 或者直接在launch参数里添加代理,跳过插件动态配置的问题 const browser = await puppeteer.launch({ args: [ '--disable-dev-shm-usage', `--proxy-server=${proxy}:1050` ], headless: false }); // 剩余业务逻辑保持不变... }
2. 确保浏览器进程彻底关闭
虽然你在代码里写了await browser.close(),但异常情况下(比如page.goto失败)可能因为某一步报错导致后续关闭代码未执行,残留的进程会引发资源和参数累积。
优化关闭逻辑:用finally块包裹关闭操作,确保无论是否报错都能执行:
try { // 你的页面访问、数据解析逻辑... } catch (err) { console.log("ERROR new " + err + ' proxy: ' + proxy); } finally { // 确保一定会执行关闭操作,避免进程残留 try { if (page) await page.close(); if (browser) { browser.disconnect(); // 先断开连接,再关闭 await browser.close(); } } catch (closeErr) { console.log('关闭浏览器时出错:', closeErr); } }
3. 限制并发浏览器实例数量
你提到启动2个浏览器约1小时出错,说明并发过高会加速参数累积和资源消耗。可以用并发控制库(比如p-limit)限制同时运行的浏览器数量:
const pLimit = require('p-limit'); const limit = pLimit(2); // 限制同时运行2个浏览器实例 function Parser(...args) { // ... // 用limit包裹getData调用,控制并发 limit(() => getData(url, ...args, proxy)) .then(result => { // 后续数据处理逻辑... }) .catch(err => { // 错误处理逻辑... }) }
4. 清理Puppeteer临时文件
Puppeteer每次启动都会生成临时用户数据目录,长时间运行可能导致这些路径相关的命令行参数过长。可以手动指定固定的用户数据目录,避免临时目录不断增加:
const browser = await puppeteer.launch({ args: ['--disable-dev-shm-usage'], headless: false, userDataDir: './fixed-browser-data' // 指定固定目录,避免临时目录累积 });
定期清理该目录下的无用文件即可(如果需要保留cookie等数据,不要清空)。
关于警告的补充
虽然你认为MaxListenersExceededWarning无关,但这个警告通常是重复注册事件监听导致的——而你重复注册代理插件的行为正好会触发这个问题。修复插件重复注册后,这个警告大概率会消失。
另外,The process with PID XXX could not be terminated的错误,也和浏览器进程未彻底关闭有关,优化关闭逻辑后应该能缓解。
内容的提问来源于stack exchange,提问作者BrothersWar

