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

如何让Scrapy生成请求时立即执行,而非等待全部请求创建完成

问题

我有一个Scrapy爬虫,会从私有Github下载包含约100万播放列表ID的文件,希望借助Chartmetric(音乐数据分析工具)对这些ID进行搜索。相关代码如下:

def start_requests(self):
        self.logger.info("starting requests")
        
        yield scrapy.Request('https://raw.githubusercontent.com/XXXX/XXXX/main/unique_playlist_ids.csv.gz',
                             method = 'GET',
                             callback = self.do_requests,
                             headers = {'Authorization': 'token XXX'})

在do_requests函数中,我会解压数据集并循环所有行来创建请求:

def do_requests(self,response):
        data = BytesIO(response.body)
        with gzip.open(data, 'rt') as f:
            reader = csv.reader(f)
            playlists = [row[0] for row in reader]
        
        for n,playlist_id in enumerate(playlists):
            search_data = {"q": "https://open.spotify.com/playlist/"+playlist_id, "type": "playlists", "limit": "1"}
            
            yield scrapy.Request(url = "https://api.chartmetric.com/api/search?" + urlencode(search_data), 
                                 method='GET',
                                 callback=self.parse_playlist,
                                 meta = {"spotify_playlist_id": playlist_id},
                                 priority = -n,
                                 dont_filter=True)

遇到的问题:Scrapy会先循环完100万行创建所有请求,之后才开始执行(并调用self.parse_playlist解析),但使用本地CSV文件时不会出现此问题。另外,有一个自定义中间件会在爬虫启动时创建并轮换3个Token以调用Chartmetric API,但这应该不影响当前问题。尝试过设置priority = -n或priority = n,均无效。需要让Scrapy在生成请求时立即执行,而非等待全部请求调度完成。

解决方案

问题根源在于你一次性将100万条数据全部加载到内存列表playlists中,必须等整个列表生成完毕,Scrapy才能开始调度请求。本地文件读取更快、内存占用压力小,所以产生了“立即执行”的错觉,但逻辑本质一致。

核心修复:边读取边生成请求

不要一次性把所有行存入列表,直接遍历csv.reader的迭代器,读取一行就生成一个请求,这样Scrapy可以在生成请求的同时立即调度执行:

def do_requests(self, response):
    data = BytesIO(response.body)
    with gzip.open(data, 'rt') as f:
        reader = csv.reader(f)
        # 直接遍历reader迭代器,无需先转成列表
        for n, row in enumerate(reader):
            playlist_id = row[0]
            search_data = {"q": f"https://open.spotify.com/playlist/{playlist_id}", "type": "playlists", "limit": "1"}
            
            yield scrapy.Request(
                url=f"https://api.chartmetric.com/api/search?{urlencode(search_data)}",
                method='GET',
                callback=self.parse_playlist,
                meta={"spotify_playlist_id": playlist_id},
                priority=-n,
                dont_filter=True
            )

可选优化:调整并发设置

即使边生成边yield,Scrapy默认并发数可能限制请求的立即执行,可在settings.py中根据目标API的限流规则调整:

# 全局并发请求数
CONCURRENT_REQUESTS = 32
# 针对Chartmetric域名的并发数
CONCURRENT_REQUESTS_PER_DOMAIN = 16

排查项:确认中间件无阻塞

临时禁用自定义Token轮换中间件,测试是否是中间件导致请求延迟调度。如果禁用后恢复正常,再检查中间件逻辑是否存在阻塞行为。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 08:57:32