Scrapy CrawlSpider多进程运行内存泄漏致服务器崩溃排查求助
Scrapy CrawlSpider内存泄漏排查解决方法
核心问题定位
你观测到Python层对象总大小仅数MB但内存占满,说明泄漏发生在C扩展层,结合你换基础Spider无问题的现象,问题出在CrawlSpider依赖的lxml解析缓存、规则编译缓存两个方向。
修复步骤
1. 修正代码不规范写法
你当前的两处写法直接导致内存累积:
- rules属性必须定义为类属性:你将rules放在
__init__内作为实例属性赋值,CrawlSpider初始化时会重复编译规则,产生的lxml XPath编译缓存不会被Python GC回收,属于C层内存泄漏。 - XPath写法低效触发缓存累积:你写的
//a[not(//footer)]每次匹配节点时都会全局扫描文档生成footer节点集,lxml的临时节点对象在C层累积,不会被Python内存统计工具检测到。
修正后的代码如下:
from scrapy.spiders import CrawlSpider, Rule from scrapy.linkextractors import LinkExtractor class wb8(CrawlSpider): name = 'wb8' # rules移至类属性,拆分规则实现需求 rules = ( # 规则1:匹配footer内的链接,优先级高 Rule( LinkExtractor(restrict_xpaths="//footer//a", unique=True), callback='parse_test', follow=True ), # 规则2:如果没有匹配到footer链接,自动走全页a提取,fallback逻辑 Rule( LinkExtractor(tags=('a',), unique=True), callback='parse_test', follow=True, process_links=lambda links: links if not any('footer' in l.url for l in links) else [] ) ) def __init__(self, bdd_id, domain, cleaned_domain, *a, **kw): self.domain = domain self.bdd_id = bdd_id self.start_urls = [domain] self.allowed_domains = [cleaned_domain] super().__init__(*a,**kw) def parse_start_url(self, response): return self.parse_test(response) def parse_test(self,response): # 处理完响应后手动删除引用,触发GC回收 res = response.text[:100] # 按需处理响应内容 del response yield {}
2. 添加Scrapy配置优化
在settings.py加入以下配置,切断缓存累积路径:
# 关闭不必要的缓存 COOKIES_ENABLED = False DOWNLOADER_STATS = False # 限制并发数,避免同时存在过多lxml解析对象 CONCURRENT_REQUESTS = 16 # 开启响应自动回收 RESPONSE_PAYLOAD_SIZE_LIMIT = 10*1024*1024 # 限制单响应最大10MB
3. 多进程场景额外处理
如果是多进程循环启动爬虫实例,每次实例运行结束后添加以下代码手动释放C层缓存:
import gc import lxml.etree # 释放lxml全局缓存 lxml.etree.cleanup_namespaces() lxml.etree.clear_error_log() # 强制Python GC回收 gc.collect()
内容的提问来源于stack exchange,提问作者IndiaSke
相关产品推荐
相关产品推荐

