Scrapy报HTTP status code is not handled or not allowed错误解决方案
错误原因
- 你遇到的
HTTP status code is not handled or not allowed报错不是请求频率过高触发的站点拦截,核心原因是请求构造不符合接口规则,被服务端拒绝后返回了Scrapy默认不处理的非200状态码。 - 代码存在基础冗余问题:同一份代码里重复导入依赖、重复定义了两次
TestSpider类,运行时前一个类定义会被直接覆盖。 - 参数位置配置错误:Algolia搜索接口要求
x-algolia-api-key、x-algolia-application-id、x-algolia-agent三个鉴权参数放在请求头中传递,你错误将其放在了POST表单参数里。 - 请求格式不匹配:你当前设置的
content-type为application/x-www-form-urlencoded,但该接口实际要求接收JSON格式的请求体,使用FormRequest发送表单数据会被接口直接拒绝,返回400/403类错误状态码。Scrapy默认仅处理200-299区间的正常响应,碰到未配置允许的状态码就会抛出该报错。
修复方案
- 清理冗余代码:删除重复的导入语句、重复的Spider类定义。
- 调整参数位置:将三个鉴权参数从params中移出,合并到headers配置里。
- 更换请求方式:放弃使用
FormRequest发送表单请求,改用Scrapy原生Request发送POST请求,请求体使用JSON序列化后的参数字符串,同时将headers中的content-type修改为application/json。 - 调试阶段可在Spider类中添加
handle_httpstatus_list = [400, 403, 429]配置,允许Scrapy将指定的错误状态码响应传递给回调函数,方便查看接口返回的具体错误信息。如果后续确实碰到频率拦截,可在settings中配置DOWNLOAD_DELAY参数增加请求间隔。
修复后可运行代码示例
import json import scrapy from scrapy.crawler import CrawlerProcess class TestSpider(scrapy.Spider): name = 'test' url = "https://xd0u5m6y4r-dsn.algolia.net/1/indexes/event-edition-eve-e6b1ae25-5b9f-457b-83b3-335667332366_en-us/query" headers = { 'Accept-Language': 'en-GB,en-US;q=0.9,en;q=0.8,pt;q=0.7', 'Connection': 'keep-alive', 'Origin': 'https://www.nationalhardwareshow.com', 'Referer': 'https://www.nationalhardwareshow.com/', 'Sec-Fetch-Dest': 'empty', 'Sec-Fetch-Mode': 'cors', 'Sec-Fetch-Site': 'cross-site', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36', 'accept': 'application/json', 'content-type': 'application/json', 'sec-ch-ua': '".Not/A)Brand";v="99", "Google Chrome";v="103", "Chromium";v="103"', 'sec-ch-ua-mobile': '?0', 'sec-ch-ua-platform': '"Windows"', # 鉴权参数移到请求头 'x-algolia-agent': 'Algolia for vanilla JavaScript 3.27.1', 'x-algolia-application-id': 'XD0U5M6Y4R', 'x-algolia-api-key': 'd5cd7d4ec26134ff4a34d736a7f9ad47', } # 请求体参数单独存放,用JSON序列化 payload = { 'query': '', 'page': 0, 'facetFilters': '', 'optionalFilters': [] } def start_requests(self): yield scrapy.Request( url=self.url, method='POST', headers=self.headers, body=json.dumps(self.payload), callback=self.parse, ) def parse(self,response): print(response.json()) if __name__ == "__main__": process = CrawlerProcess() process.crawl(TestSpider) process.start()
内容的提问来源于stack exchange,提问作者Amen Aziz
相关产品推荐
相关产品推荐

