Python Scrapy 爬虫执行近4万次请求后运行停滞问题求助
问题排查结论
先直接排掉你怀疑的两个写法问题:
- 用默认
parse方法名完全是Scrapy的标准用法,你导入了CrawlSpider但没配置Rule也不会触发功能异常 - 把读CSV得到的URL列表直接赋值给类属性
start_urls是完全合规的写法,7.5万条URL的内存占用根本不会触发内存溢出类故障 - 现在爬取卡死的问题,和这两处写法没有关联
导致停滞的实际原因
结合你贴的日志表现,对照Scrapy的内部运行逻辑,基本是这几个问题叠加触发的:
- 并发槽位被挂起的坏请求占满
你现在只配了超时时间、关了重试、限了重定向次数,完全没调整Scrapy的默认并发参数:默认全局并发数16、单域名并发数8。当碰到大量无响应的坏URL时,所有并发槽位会被这些等待超时的请求全部占住,在10s的超时窗口期里,调度器没有空闲槽位发送新请求,就会出现日志计数完全不动的假卡死状态。
虽然你关了重试,理论上超时的请求到点就丢弃,但碰到半开的TCP连接、服务端不回包的半连接场景,操作系统层面的TCP重传等待时间比你设置的应用层超时长,很容易把槽位长时间占住。 - Item队列积压堵死管线
你代码里没有配置落盘的Item管道,所有生成的Item全暂存在Scrapy内置的内存队列里。爬了4万多页、攒了1.6万Item的时候,如果队列消费速度跟不上生产速度,队列一满,parse方法根本没法yield新的Item,整个采集管线直接卡死,表现和请求层停滞完全一致,很难直接区分。 - 主机临时端口被TIME_WAIT连接占满
无延时高频发起7.5万量级的HTTP请求时,会生成大量处于TIME_WAIT状态的TCP连接,把主机的临时端口池占满,新的TCP连接根本建立不起来,所有请求卡在连接建立阶段,你设置的应用层超时都无法生效,直接表现就是爬取速率掉到0彻底不动。
可直接落地的修复方案
在你原来的custom_settings里追加上这些配置,基本能解决卡死问题:
custom_settings = { # 保留你之前写的原有配置 'DNS_TIMEOUT': 10, 'DOWNLOAD_TIMEOUT': 10, 'RETRY_ENABLED': False, 'REDIRECT_MAX_TIMES': 2, # 追加配置解决卡死问题 'CONCURRENT_REQUESTS': 32, 'CONCURRENT_REQUESTS_PER_DOMAIN': 4, 'DOWNLOAD_DELAY': 0.2, 'ROBOTSTXT_OBEY': False, 'COOKIES_ENABLED': False, 'SCHEDULER_DISK_QUEUE': 'scrapy.squeues.PickleLifoDiskQueue', # 用磁盘队列替代纯内存队列,降低内存占用同时避免任务丢失 'ITEM_PIPELINES': { # 在这里配置实际落盘的管道,不要让所有Item全攒在内存里 } }
额外提醒:你现在把日志级别设成了INFO,只能看到爬取计数,根本看不到底层的报错,把日志级别改成DEBUG,下次复现卡死的时候就能定位到具体卡在哪一步,不用靠猜测排查。
内容的提问来源于stack exchange,提问作者mustacheMcGee
相关产品推荐
相关产品推荐

