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

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}
            )

关键修复点说明

  1. 正确格式化URL:使用Python的f-string语法动态替换页码,确保每个请求的URL都是有效的。
  2. 改用递归请求逻辑:去掉start_requests中的同步循环,改为在parse方法处理完当前页后,根据响应状态决定是否生成下一页请求,实现动态爬取控制。
  3. 允许处理422响应:添加handle_httpstatus_list = [422]配置,让Scrapy将422状态码的响应传递给parse方法,这样就能在回调中判断是否停止爬取。
  4. 简化错误判断逻辑:直接通过422状态码识别“无更多内容”的情况,无需解析复杂的错误响应结构(若需更精细的错误处理可保留原解析逻辑)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 00:24:51