Scrapy爬虫请求异常:回调未执行且循环生成无效请求
Scrapy爬虫问题分析与修复方案
核心问题拆解
从代码和运行日志能看出三个致命问题:
- URL格式化失败:请求URL中的
{page}未被替换为实际页码,导致所有请求都指向无效地址https://web-scraping.dev/api/testimonials?page={page},服务器返回422状态码。 - 同步循环逻辑错误:
start_requests中的while循环是同步执行的,会瞬间生成大量重复请求,而self.scroll的修改是在异步回调中,根本无法终止循环。 - 非200响应被拦截:Scrapy默认的
HttpErrorMiddleware会忽略422这类非成功状态码的响应,导致你的parse方法完全无法处理这些错误响应。
修复后的完整代码
class ScrollSpider(scrapy.Spider): name = 'scroll' # 允许处理422状态码,让这类响应进入parse方法 handle_httpstatus_list = [422] headers={ "Referer": "https://web-scraping.dev/testimonials", "X-Secret-Token": "secret123", } def start_requests(self): # 仅初始化第一页请求,后续请求在parse中递归生成 yield scrapy.Request( url=f'https://web-scraping.dev/api/testimonials?page=1', headers=self.headers, callback=self.parse, meta={'page': 1} # 将页码存入meta,用于生成下一页 ) def parse(self, response): if response.status == 422: self.logger.info("已爬取至最后一页,终止请求") return if response.status == 200: testimonials = response.css('div.testimonial') for testimonial in testimonials: yield { 'user_name': testimonial.css('identicon-svg::attr(username)').get(), 'user_photo': testimonial.css('svg::attr(src)').get(), 'testimonial': testimonial.css('p::text').get(), 'rating': len(testimonial.css('span svg').getall()) } # 生成下一页请求 next_page = response.meta['page'] + 1 yield scrapy.Request( url=f'https://web-scraping.dev/api/testimonials?page={next_page}', headers=self.headers, callback=self.parse, meta={'page': next_page} )
关键修复点说明
- 正确格式化URL:使用Python的f-string语法动态替换页码,确保每个请求的URL都是有效的。
- 改用递归请求逻辑:去掉
start_requests中的同步循环,改为在parse方法处理完当前页后,根据响应状态决定是否生成下一页请求,实现动态爬取控制。 - 允许处理422响应:添加
handle_httpstatus_list = [422]配置,让Scrapy将422状态码的响应传递给parse方法,这样就能在回调中判断是否停止爬取。 - 简化错误判断逻辑:直接通过422状态码识别“无更多内容”的情况,无需解析复杂的错误响应结构(若需更精细的错误处理可保留原解析逻辑)。
内容的提问来源于stack exchange,提问作者TEOTU
相关产品推荐
相关产品推荐

