Scrapy爬取大量URL时内存不足被终止,如何流式读取URL?
如何在Scrapy中流式读取URL避免内存不足?
当然可以!你当前的写法是把urls.txt里的所有URL一次性加载到内存中,当文件里的URL数量达到几万甚至几百万级时,内存占用直接拉满,被系统终止也很正常。下面给你两种实用的流式读取方案,都是Scrapy生态里常用的思路:
方法一:重写start_requests方法(最推荐)
Scrapy的Spider默认会把start_urls里的所有URL一次性生成Request,我们可以通过重写start_requests方法,改成逐行读取文件并生成Request,这样每次内存里只会保留当前处理的那一行URL,完全不会有内存溢出的问题。
代码示例:
import scrapy class YourSpider(scrapy.Spider): name = 'your_spider_name' def start_requests(self): # 用with语句自动管理文件句柄,逐行读取 with open('urls.txt', 'r', encoding='utf-8') as f: for line in f: url = line.strip() # 跳过空行,避免生成无效的Request if url: yield scrapy.Request(url=url, callback=self.parse) def parse(self, response): # 你的解析逻辑 pass
为什么这方法好用?
- 流式读取:每次只加载一行数据到内存,处理完就释放,内存占用极低
- 代码改动小:替换原来的
start_urls定义即可,不需要修改核心解析逻辑 - 自动去重:Scrapy默认的去重机制依然会对这些Request生效,不用担心重复爬取
方法二:使用生成器函数封装URL读取(适合复杂场景)
如果你的URL来源不止一个文件,或者需要对URL做预处理(比如批量添加前缀、过滤特定域名),可以把URL读取逻辑封装成一个生成器函数,再在start_requests里调用:
def get_urls(): with open('urls.txt', 'r', encoding='utf-8') as f: for line in f: url = line.strip() if url and url.startswith('https://'): # 额外过滤条件 yield url class YourSpider(scrapy.Spider): name = 'your_spider_name' def start_requests(self): for url in get_urls(): yield scrapy.Request(url=url, callback=self.parse) def parse(self, response): # 你的解析逻辑 pass
额外注意事项
- 如果你的URL文件编码不是UTF-8,记得在
open()里指定对应的encoding参数(比如gbk) - 如果文件特别大(比如几十GB),可以考虑分块读取,但逐行读取已经能覆盖绝大多数场景
- 要是需要断点续爬,可以结合Scrapy的
JOBDIR功能,避免重新处理已经爬过的URL
内容的提问来源于stack exchange,提问作者Julian Medic




