You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Scrapy POST请求Payload格式问题及404错误排查咨询

解决Scrapy请求Storia Imóveis AJAX接口404错误的疑问解答

先结合你的代码和问题逐一拆解分析:


1. Scrapy请求携带的Payload是否需要特定类型或格式?

是的,完全取决于目标接口的要求。从你设置的Content-Type: application/json可以看出,这个接口要求JSON格式的请求体,所以你的Payload必须是符合JSON规范的字符串,同时结构要和浏览器发送的请求体完全匹配(包括字段名称、嵌套层级、数据类型)。比如你Payload里的经纬度是数字类型,这就和原请求一致,不能随便改成字符串。

另外要注意,接口依赖的sessionId是硬编码的,这很可能已经过期失效——这也是导致404的常见原因之一,建议从起始页的HTML或Cookie中动态提取有效的sessionId

2. 是否需要调用json.dumps(payload)后再发送,还是直接发送字典?

在Scrapy的Request中,如果你的Content-Typeapplication/json,必须用json.dumps()把Python字典转换成JSON字符串,然后赋值给body参数。如果直接传字典,Scrapy会把它当成表单数据处理,接口无法识别,必然返回错误。你代码里的body=json.dumps(self.payload)这部分是正确的。

3. 是否需要将Payload的所有键值对转为字符串?

不需要!json.dumps()会自动处理Python的基础数据类型(数字、布尔值、列表、字典),把它们转换成符合JSON规范的格式。比如你Payload里的经纬度是数字,就应该保持数字类型,如果强行转成字符串,反而会和接口预期的格式不符,导致请求失败。

4. 还有哪些可能导致请求失败?

除了上面提到的点,还有几个常见的坑:

  • URL参数错误:你start_urls里的API URL用了&(HTML转义符),这是错误的,应该直接用&,否则URL会被解析错误,返回404。
  • 初始请求逻辑错误:你的start_urls直接写了API地址,Scrapy默认会发送GET请求,但这个接口需要POST,所以初始的GET请求就会返回404。正确的做法是把起始页设为https://www.storiaimoveis.com.br/alugar/brasil,在parse方法中处理起始页的响应,提取必要的参数(比如sessionId)后,再构造POST请求到API接口。
  • SessionId过期/无效:你硬编码的sessionId大概率是临时的,网站会定期失效,必须从浏览器请求中动态获取(比如查看起始页的Cookie、HTML中的脚本变量)。
  • 缺少必要的请求头:除了你现有的头,可能还需要添加X-Requested-With: XMLHttpRequest(很多AJAX接口会校验这个),或者Accept-Language等头,建议用浏览器开发者工具对比原请求的所有头信息。
  • 反爬机制拦截:你的User-Agent是Chrome 75,版本太旧了,网站可能会识别为爬虫。建议换成最新的Chrome/Firefox的User-Agent,或者添加Cookie字段(从浏览器复制有效Cookie测试)。

修正后的代码片段参考

import scrapy
import json
from scrapy.spiders import CrawlSpider

class MySpider(CrawlSpider):
    name = 'myspider'
    # 起始页改为网站首页,而非API接口
    start_urls = ['https://www.storiaimoveis.com.br/alugar/brasil']

    headers = {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
        'Referer': 'https://www.storiaimoveis.com.br/alugar/brasil',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36',
        'X-Requested-With': 'XMLHttpRequest'  # 添加AJAX标识头
    }

    def parse(self, response):
        # 这里可以从响应中提取动态的sessionId,比如从Cookie中获取(示例逻辑,需根据实际调整)
        session_id = ""
        for cookie in response.headers.getlist('Set-Cookie'):
            cookie_str = cookie.decode('utf-8')
            if 'sessionId' in cookie_str:
                session_id = cookie_str.split('sessionId=')[1].split(';')[0]
                break
        
        # 构造正确的API URL,替换&为&
        api_url = f'https://www.storiaimoveis.com.br/api/search?fields=$$meta.geo.postalCodeAddress.city,$$meta.geo.postalCodeAddress.neighborhood,$$meta.geo.postalCodeAddress.street,$$meta.location,$$meta.created,address.number,address.postalCode,address.neighborhood,address.state,media,livingArea,totalArea,types,operation,salePrice,rentPrice,newDevelopment,administrationFee,yearlyTax,account.logoUrl,account.name,account.id,account.creci,garage,bedrooms,suites,bathrooms,ref&optimizeMedia=true&size=20&from=0&sessionId={session_id}'
        
        payload = {
            "locations":[{"geo":{"top_left":{"lat":5.2717863, "lon":-73.982817}, "bottom_right":{"lat":-34.0891, "lon":-28.650543}}, "placeId":"ChIJzyjM68dZnAARYz4p8gYVWik", "keywords":"Brasil", "address":{"label":"Brasil","country":"BR"}}],
            "operation":["RENT"],
            "bathrooms":[],
            "bedrooms":[],
            "garage":[],
            "features":[]
        }
        
        yield scrapy.Request(
            url=api_url,
            method='POST',
            headers=self.headers,
            body=json.dumps(payload),
            callback=self.parse_items
        )

    def parse_items(self, response):
        from scrapy.shell import inspect_response
        inspect_response(response, self)
        print(response.text)

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

火山引擎 最新活动