Scrapy解析回调中无法发送请求问题咨询
问题分析与解决方案
你遇到的核心问题是:Scrapy的请求调度系统只能识别由Spider实例生成并yield的Request对象,而你的CommentParser是一个独立的类,它的方法里yield的Request并没有被Scrapy引擎捕获——因为这些请求没有经过Spider实例的处理流程。
解决方法1:将解析逻辑整合到Spider类内部
这是最直接的方式,把CommentParser的方法移到SiteSpider里,让请求从Spider实例中yield出来:
import scrapy class SiteSpider(scrapy.Spider): name = "somesite" start_urls = ['https://www.somesite.com'] def start_requests(self): urls = ['https://www.somesite.com'] for url in urls: yield scrapy.Request(url=url, callback=self.scrape) def scrape(self, response): print("from scrape =>", response.url) for i in range(5): # 这里的Request由Spider实例yield,会被Scrapy引擎调度 yield scrapy.Request(url="https://www.somesite.com/comments/?page=%d" % i, callback=self.parse) def parse(self, response): print("from parse => ", response.url) yield dict(response_url = response.url)
解决方法2:让独立的解析类与Spider协作
如果你想保留CommentParser的独立结构,可以让它的方法返回Request列表,然后在Spider的回调里yield这些请求:
import scrapy class CommentParser(): def scrape(self, response): print("from CommentParser.scrape =>", response.url) requests = [] for i in range(5): requests.append(scrapy.Request(url="https://www.somesite.com/comments/?page=%d" % i, callback=self.parse)) return requests def parse(self,response): print("from CommentParser.parse => ", response.url) yield dict(response_url = response.url) class SiteSpider(scrapy.Spider): name = "somesite" start_urls = ['https://www.somesite.com'] def start_requests(self): self.parser = CommentParser() urls = ['https://www.somesite.com'] for url in urls: yield scrapy.Request(url=url, callback=self.handle_scrape) def handle_scrape(self, response): # 接收CommentParser返回的请求列表,逐个yield给Scrapy引擎 for req in self.parser.scrape(response): # 确保回调函数能被Scrapy正确调度 yield req
为什么原来的代码不行?
Scrapy的引擎会跟踪Spider实例中所有yield的Request,而外部类CommentParser的方法里yield的Request,不在Spider的上下文里,Scrapy无法感知到这些请求的存在,自然不会去调度执行。只有当请求从Spider的回调方法中yield出来,才会被引擎加入到请求队列中。
内容的提问来源于stack exchange,提问作者mo.nasiri
相关产品推荐
相关产品推荐

