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

Docker中Arsenic异步爬取出现net::ERR_CONNECTION_CLOSED错误求助

问题分析与解决办法

一、bind()失败但不影响启动的原因

多个ChromeDriver启动时出现bind()失败,本质是端口分配的竞争问题:Arsenic尝试绑定端口时,部分刚被释放的端口处于TIME_WAIT状态,导致临时绑定失败,但ChromeDriver会自动重试其他可用端口,因此不影响正常启动。这属于Docker环境下端口复用的常见现象,一般无需过度担忧,但若要优化可自定义端口范围,避免端口冲突。

二、unknown error: net::ERR_CONNECTION_CLOSED错误的核心原因及解决

该错误是Chrome实例与目标网站的连接被异常中断,结合你的异步爬虫场景与Docker环境,具体原因及修复方案如下:

1. 目标网站反爬机制触发

企业网站普遍有反爬策略,即使将Semaphore降至20,短时间内同一IP的请求量仍可能触发服务器主动关闭连接。

  • 解决措施:
    • 给每个Chrome实例配置随机User-Agent,避免统一标识暴露爬虫身份
    • 在异步任务中加入随机请求间隔,比如asyncio.sleep(random.uniform(1,3)),避免固定频率请求
    • 若有代理资源,给不同Chrome实例分配不同代理IP,分散请求来源

2. Docker资源配额不足

RHEL7 Docker镜像默认资源限制较低,Chrome是资源密集型程序,20个并发实例可能导致CPU、内存耗尽,引发连接中断。

  • 解决措施:
    • 启动Docker容器时增加资源分配,例如--cpus=4 --memory=8g(根据宿主机实际资源调整)
    • 在Chrome启动参数中添加资源限制,比如--max-memory-limit=512m、--cpu-per-thread=0.5,降低单个Chrome实例的资源占用

3. Chrome运行依赖缺失或启动参数不合理

Docker环境下的Chrome可能缺少必要依赖库,或启动参数配置不当导致网络连接不稳定。

  • 解决措施:
    • 强制添加Docker环境必备的Chrome启动参数:--no-sandbox、--disable-dev-shm-usage,避免共享内存不足问题
    • 确保Docker镜像中安装Chrome运行所需依赖,比如glibc、libnss3、libx11-xcb1等(RHEL7需额外安装)
    • 给Arsenic明确指定ChromeDriver的绝对路径,避免自动查找时出现版本不匹配

4. 异步并发控制失效

Semaphore设置为20,但可能因异步任务调度逻辑问题,实际并发数超出预期,或Arsenic连接池管理存在漏洞。

  • 解决措施:
    • 检查代码中Semaphore的使用是否严格生效,确保每个爬取任务都用async with sem:包裹
    • 尝试进一步降低Semaphore至10或更低,逐步测试目标网站能承受的并发上限
    • 优化异步任务调度逻辑,比如用asyncio.gather配合Semaphore,避免任务堆积

三、优化后的代码示例

import asyncio
import random
import logging
from arsenic import get_session, browsers, services

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# Chrome启动参数优化
chrome_options = {
    "args": [
        "--no-sandbox",
        "--disable-dev-shm-usage",
        "--max-memory-limit=512m",
        "--disable-gpu",
        # 随机User-Agent
        f"user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36_{random.randint(1000,9999)}"
    ]
}

async def crawl_url(url, sem):
    async with sem:
        try:
            logger.info(f"开始爬取: {url}")
            # 指定ChromeDriver路径
            service = services.Chromedriver(binary='/usr/local/bin/chromedriver')
            browser = browsers.Chrome(**chrome_options)
            async with get_session(service, browser) as session:
                await session.get(url)
                # 此处添加你的爬取逻辑
                # 随机请求间隔
                await asyncio.sleep(random.uniform(1.5, 3.5))
            logger.info(f"爬取完成: {url}")
        except Exception as e:
            logger.error(f"爬取{url}失败: {str(e)}")

async def main():
    # 进一步降低并发量测试
    sem = asyncio.Semaphore(15)
    urls = ["https://target-enterprise-site.com/page1", "https://target-enterprise-site.com/page2"]
    tasks = [crawl_url(url, sem) for url in urls]
    # 允许任务异常返回,不中断整体爬取
    await asyncio.gather(*tasks, return_exceptions=True)

if __name__ == "__main__":
    asyncio.run(main())

四、日志排查建议

针对net::ERR_CONNECTION_CLOSED错误,建议在代码中增加系统资源日志(如CPU、内存占用),结合请求URL和时间戳,精准定位是资源耗尽还是反爬触发:

import psutil

# 在异常捕获中添加资源日志
except Exception as e:
    cpu_usage = psutil.cpu_percent()
    mem_usage = psutil.virtual_memory().percent
    logger.error(f"爬取{url}失败: {str(e)} | CPU占用: {cpu_usage}% | 内存占用: {mem_usage}%")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 18:46:02