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

Scrapy+Playwright爬取电商站遇EPIPE错误及内存溢出问题

解决Scrapy+Playwright爬取时EPIPE崩溃与内存泄漏问题

问题根源

EPIPE错误源于Node.js(Playwright依赖)与浏览器实例的通信中断,结合内存持续飙升,核心原因是浏览器页面/上下文/实例未被正确销毁,资源无法释放导致内存耗尽。之前设置的NODE_OPTIONS="--max-old-space-size=8192"仅扩大了Node.js内存上限,属于治标不治本的临时方案。

修复步骤

1. 显式销毁Playwright资源

爬取完成后必须手动关闭页面/上下文,拒绝依赖自动回收:

async def parse(self, response):
    page = response.meta["playwright_page"]
    
    # 执行爬取逻辑...
    
    # 强制关闭页面
    await page.close()
    # 若使用了独立上下文,同步关闭
    # await response.meta["playwright_context"].close()

2. 严格限制并发实例数量

过高的并发会导致Playwright创建大量浏览器资源,直接拉满内存。修改settings.py:

# Scrapy全局并发控制
CONCURRENT_REQUESTS = 16
# Playwright上下文与页面并发限制
PLAYWRIGHT_CONCURRENT_CONTEXT = 4
PLAYWRIGHT_MAX_PAGES_PER_CONTEXT = 4

3. 启用自动页面回收

不需要保留页面对象时,通过配置让Playwright自动关闭页面:

def start_requests(self):
    yield scrapy.Request(
        url="https://target-ecommerce.com",
        meta={
            "playwright": True,
            "playwright_page_coroutines": [PageCoroutine("wait_for_selector", ".product-card")],
            "playwright_include_page": False,  # 自动关闭页面,释放资源
        },
    )

4. 清理页面事件监听

绑定的request/response等事件监听若未移除,会持续占用内存:

async def parse(self, response):
    page = response.meta["playwright_page"]
    
    # 定义监听函数
    def log_request(request):
        self.logger.debug(f"Request: {request.url}")
    
    # 绑定监听
    page.on("request", log_request)
    
    # 爬取逻辑...
    
    # 移除监听并关闭页面
    page.remove_listener("request", log_request)
    await page.close()

5. 配合Node.js内存参数优化

保留之前的内存配置,但需结合上述修复使用:

export NODE_OPTIONS="--max-old-space-size=8192"
scrapy crawl ecommerce_spider

6. 定期重启浏览器实例

若内存泄漏仍存在,可设置每爬取N条数据后重启浏览器:

from scrapy_playwright.handler import PlaywrightHandler

class EcommerceSpider(scrapy.Spider):
    name = "ecommerce_spider"
    crawl_count = 0
    RESTART_THRESHOLD = 1000  # 每爬1000条重启浏览器

    async def parse(self, response):
        self.crawl_count += 1
        if self.crawl_count % self.RESTART_THRESHOLD == 0:
            # 获取Playwright处理器并重启浏览器
            handler = self.crawler.engine.downloader.middleware.middlewares[0].handler
            await handler.close()
            await handler._launch_browser()
        
        # 爬取逻辑...

验证方式

  • 用htop(Linux)或任务管理器(Windows)监控内存,若内存稳定在合理区间,说明修复有效。
  • 检查日志,确认EPIPE错误不再出现。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 10:55:17