如何在Scrapy中循环请求API直至返回空JSON时终止?
问题:Scrapy动态遍历API分页并终止请求循环
我需要在Scrapy的start_requests方法中发起动态次数的请求,用来遍历某API的所有分页。事先不知道总页数,但知道当请求页数超出范围时,API会返回空JSON。我想实现类似如下逻辑,但不知道怎么在返回空JSON时终止请求循环:
url = "https://example.com?page={}" def start_requests(self): page = 0 while True: page += 1 yield scrapy.Request(url=url.format(page), callback=self.parse) def parse(self, response, **kwargs): data = json.loads(response.body) if 'key' in data: # 解析并生成Item pass else: # 不生成Item,同时终止start_requests里的while循环
请问满足条件时,能否从parse回调返回值(而非yield)来终止循环?
解决方案
不能直接通过parse回调的返回值终止start_requests里的while循环,原因是Scrapy的请求处理是异步的:start_requests作为生成器会一次性把大量(甚至无限)请求推入调度队列,等parse回调执行时,循环早就已经生成了很多多余的请求,根本没法回溯终止。
正确的实现方式是采用递归式的请求触发:在parse方法里判断当前页是否有有效数据,有则解析数据并生成下一页的请求;没有则停止生成新请求,自然终止分页遍历。
修改后的代码示例:
import json import scrapy class YourSpider(scrapy.Spider): name = "your_spider" base_url = "https://example.com?page={}" def start_requests(self): # 从第1页开始 yield scrapy.Request(url=self.base_url.format(1), callback=self.parse, meta={'page': 1}) def parse(self, response, **kwargs): current_page = response.meta.get('page') data = json.loads(response.body) if 'key' in data: # 解析数据并生成Item for item in data['key']: # 这里根据实际结构生成Item yield { 'field1': item.get('field1'), 'field2': item.get('field2') } # 生成下一页请求,把当前页码+1传入meta next_page = current_page + 1 yield scrapy.Request( url=self.base_url.format(next_page), callback=self.parse, meta={'page': next_page} ) else: # 没有有效数据,停止生成新请求,遍历自动终止 return
逻辑说明
- 初始请求从第1页发起,通过
meta参数传递当前页码 - 在
parse中解析响应:- 如果存在有效数据(
'key' in data),先解析生成Item,再生成下一页的请求 - 如果返回空JSON,直接
return不生成新请求,整个分页遍历就会停止
- 如果存在有效数据(
- 这种方式完全是按需生成请求,不会出现多余的无效请求,也不需要提前知道总页数
内容的提问来源于stack exchange,提问作者bcsta
相关产品推荐
相关产品推荐

