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

求助:解决Node.js Puppeteer的TargetCloseError(Protocol error Network.enable)

问题:Puppeteer爬虫出现TargetCloseError: Protocol error (Network.enable): Target closed错误

我用Node.js的Puppeteer开发了一个网络爬虫,运行时遇到错误:TargetCloseError: Protocol error (Network.enable): Target closed。发现这个错误常出现在快速打开并关闭大量标签页时,推测是浏览器过载导致的。

我的代码

import vanillaPuppeteer from 'puppeteer'
import {addExtra} from "puppeteer-extra";
import StealthPlugin from 'puppeteer-extra-plugin-stealth'
import AdblockerPlugin from "puppeteer-extra-plugin-adblocker";
import dotenv from 'dotenv'
import axios from "axios";
import * as cheerio from 'cheerio';
import {Cluster} from "puppeteer-cluster";

...

const fetchData = async (query) => {
    try {
        return await axios.post('https://eintaxid.com/search-ajax.php', `&query=${query}`)
    } catch (error) {
        throw error
    }
}

(async () => {
    dotenv.config()

    const puppeteer = addExtra(vanillaPuppeteer)
    puppeteer.use(StealthPlugin())
    puppeteer.use(AdblockerPlugin())

    const queries = process.env.QUERIES.split(',')
    for (const query of queries) {
        const {data: content} = await fetchData(query)
        const $ = cheerio.load(content)

        const links = []
        $('a').each((i, a) => {
            const href = $(a).attr('href')
            links.push(`https://eintaxid.com${href}`)
        })

        const cluster = await Cluster.launch({
            puppeteer,
            concurrency: Cluster.CONCURRENCY_CONTEXT,
            maxConcurrency: 2,
            puppeteerOptions: {
                defaultViewport: false,
                headless: false,
                args: ['--no-sandbox']
            }
        })

        await cluster.task(async ({page, data: link}) => {
            await page.goto(link, {
                waitUntil: 'networkidle2'
            })
            const data = await parseData(await page.content())
            console.log(data)
        })

        for (const link of links) {
            cluster.queue(link)
        }

        await cluster.idle()
        await cluster.close()
    }
})()

package.json依赖

"dependencies": {
    "axios": "^1.5.0",
    "cheerio": "^1.0.0-rc.12",
    "dotenv": "^16.3.1",
    "puppeteer": "^21.2.1",
    "puppeteer-cluster": "^0.23.0",
    "puppeteer-extra": "^3.3.6",
    "puppeteer-extra-plugin-adblocker": "^2.13.6",
    "puppeteer-extra-plugin-stealth": "^2.11.2",
    "uuid": "^9.0.1"
  }

.env文件内容

QUERIES=Repair,Rent

错误信息

file:///D:/Work/Orders/RG/eintaxid.com-scraper/node_modules/puppeteer-core/lib/esm/puppeteer/common/Connection.js:142
            this._reject(callback, new TargetCloseError('Target closed'));
                                   ^

TargetCloseError: Protocol error (Network.enable): Target closed
    at CallbackRegistry.clear (file:///D:/Work/Orders/RG/eintaxid.com-scraper/node_modules/puppeteer-core/lib/esm/puppeteer/common/Connection.js:142:36)
    at CDPSessionImpl._onClosed (file:///D:/Work/Orders/RG/eintaxid.com-scraper/node_modules/puppeteer-core/lib/esm/puppeteer/common/Connection.js:493:25)       
    at Connection.onMessage (file:///D:/Work/Orders/RG/eintaxid.com-scraper/node_modules/puppeteer-core/lib/esm/puppeteer/common/Connection.js:251:25)
    at WebSocket.<anonymous> (file:///D:/Work/Orders/RG/eintaxid.com-scraper/node_modules/puppeteer-core/lib/esm/puppeteer/common/NodeWebSocketTransport.js:46:32)
    at callListener (D:\Work\Orders\RG\eintaxid.com-scraper\node_modules\ws\lib\event-target.js:290:14)
    at WebSocket.onMessage (D:\Work\Orders\RG\eintaxid.com-scraper\node_modules\ws\lib\event-target.js:209:9)
    at WebSocket.emit (node:events:514:28)
    at Receiver.receiverOnMessage (D:\Work\Orders\RG\eintaxid.com-scraper\node_modules\ws\lib\websocket.js:1192:20)
    at Receiver.emit (node:events:514:28)
    at Receiver.dataMessage (D:\Work\Orders\RG\eintaxid.com-scraper\node_modules\ws\lib\receiver.js:558:14) {
  cause: ProtocolError
      at <instance_members_initializer> (file:///D:/Work/Orders/RG/eintaxid.com-scraper/node_modules/puppeteer-core/lib/esm/puppeteer/common/Connection.js:46:14)
      at new Callback (file:///D:/Work/Orders/RG/eintaxid.com-scraper/node_modules/puppeteer-core/lib/esm/puppeteer/common/Connection.js:50:16)
      at CallbackRegistry.create (file:///D:/Work/Orders/RG/eintaxid.com-scraper/node_modules/puppeteer-core/lib/esm/puppeteer/common/Connection.js:89:26)       
      at Connection._rawSend (file:///D:/Work/Orders/RG/eintaxid.com-scraper/node_modules/puppeteer-core/lib/esm/puppeteer/common/Connection.js:210:26)
      at CDPSessionImpl.send (file:///D:/Work/Orders/RG/eintaxid.com-scraper/node_modules/puppeteer-core/lib/esm/puppeteer/common/Connection.js:458:33)
      at NetworkManager.addClient (file:///D:/Work/Orders/RG/eintaxid.com-scraper/node_modules/puppeteer-core/lib/esm/puppeteer/common/NetworkManager.js:92:20)  
      at FrameManager.initialize (file:///D:/Work/Orders/RG/eintaxid.com-scraper/node_modules/puppeteer-core/lib/esm/puppeteer/common/FrameManager.js:181:54)    
      at FrameManager.onAttachedToTarget (file:///D:/Work/Orders/RG/eintaxid.com-scraper/node_modules/puppeteer-core/lib/esm/puppeteer/common/FrameManager.js:235:19)
      at #onAttachedToTarget (file:///D:/Work/Orders/RG/eintaxid.com-scraper/node_modules/puppeteer-core/lib/esm/puppeteer/common/Page.js:262:28)
      at file:///D:/Work/Orders/RG/eintaxid.com-scraper/node_modules/puppeteer-core/lib/esm/third_party/mitt/index.js:1:243
}

Node.js v18.17.1

我找了很多方案都没解决,求可行的解决办法?


解决方案

你的核心问题是在循环里重复创建并销毁Cluster实例,每次处理一个query就启动关闭一次浏览器集群,频繁的浏览器启动关闭操作导致了目标连接断开的错误。另外,插件加载和并发配置也可以优化,具体修复步骤如下:

1. 把Cluster实例移到循环外,复用浏览器资源

不要在每个query的循环里创建Cluster,而是全局只创建一次,把所有query对应的链接都加入队列,避免频繁启动关闭浏览器:

修改后的核心代码:

(async () => {
    dotenv.config()

    const puppeteer = addExtra(vanillaPuppeteer)
    puppeteer.use(StealthPlugin())
    puppeteer.use(AdblockerPlugin())

    // 全局创建一次Cluster
    const cluster = await Cluster.launch({
        puppeteer,
        concurrency: Cluster.CONCURRENCY_CONTEXT,
        maxConcurrency: 2,
        puppeteerOptions: {
            defaultViewport: false,
            headless: false,
            args: ['--no-sandbox', '--disable-gpu', '--disable-dev-shm-usage'] // 加上额外的优化参数
        }
    })

    await cluster.task(async ({page, data: link}) => {
        try {
            await page.goto(link, {
                waitUntil: 'networkidle2',
                timeout: 30000 // 增加超时时间,避免页面加载卡住
            })
            const data = await parseData(await page.content())
            console.log(data)
        } catch (pageError) {
            console.error(`处理链接失败: ${link}`, pageError)
            // 可以在这里添加重试逻辑
        }
    })

    const queries = process.env.QUERIES.split(',')
    for (const query of queries) {
        const {data: content} = await fetchData(query)
        const $ = cheerio.load(content)

        $('a').each((i, a) => {
            const href = $(a).attr('href')
            if (href) { // 增加空值判断,避免无效链接
                cluster.queue(`https://eintaxid.com${href}`)
            }
        })
    }

    await cluster.idle()
    await cluster.close()
})()

2. 添加浏览器启动优化参数

在puppeteerOptions的args里加上以下参数,减少浏览器资源占用:

  • --disable-gpu:禁用GPU加速,减少资源消耗
  • --disable-dev-shm-usage:避免/dev/shm内存不足的问题
  • --single-process(可选):单进程模式,适合低资源环境

3. 增加错误处理和超时机制

在page.goto时添加timeout,并且在task里包裹try-catch,避免单个页面的错误导致整个集群崩溃。

4. 调整并发策略

如果还是出现过载问题,可以降低maxConcurrency到1,或者改用Cluster.CONCURRENCY_PAGE模式(复用页面而不是上下文),进一步减少资源消耗:

concurrency: Cluster.CONCURRENCY_PAGE,
maxConcurrency: 1, // 单页面复用

5. 检查插件兼容性

部分puppeteer-extra插件可能和高版本Puppeteer(21.x)存在兼容问题,可以尝试降级Puppeteer到20.x版本,或者暂时禁用AdblockerPlugin测试是否是插件导致的连接问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 01:59:54