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

Scrapy爬取Immobilienscout24页面JSON报JSONDecodeError如何解决

Scrapy抓取ImmoScout24接口报JSONDecodeError修复方案

问题根因

抛出JSONDecodeError的核心原因是你拿到的响应根本不是预期的JSON格式,而是站点返回的HTML拦截页/验证码页,和切换VPN、补全常规请求头没有直接关系,具体问题点有两个:

  • 跳过了会话初始化流程:该站点反爬规则要求客户端必须先访问无参数的基础搜索页,拿到服务端下发的会话校验cookie之后,发送带筛选参数的XHR请求才会返回JSON数据。你直接请求带参数的接口,服务端识别到请求携带的cookie不合法,直接返回拦截页,自然无法解析JSON。
  • 请求头配置错误:GET请求不需要添加content-type: application/json头,这个头仅用于请求体为JSON格式的POST请求,添加该头反而会直接触发反爬规则。

修复步骤

  • 先模拟浏览器首次访问逻辑,第一步先请求不带任何参数的基础搜索页,让爬虫自动保存服务端下发的合法cookie,再发起带筛选参数的接口请求。
  • 移除GET请求中冗余错误的content-type请求头,请求头字段尽量和真实浏览器请求顺序保持一致,不要随意增删非必要字段。
  • 增加响应校验逻辑,不要直接调用response.json(),先判断响应的Content-Type是否为application/json,如果返回HTML内容就触发重试、重新刷新cookie,避免硬解析报错。
  • 控制请求频率,单IP请求间隔保持在3秒以上,降低触发验证码拦截的概率。

修复后代码示例

Scrapy版本

import scrapy
import urllib

class ImmobilienScoutSpider(scrapy.Spider):
    name = "immobilienscout"
    base_url = "https://www.immobilienscout24.de/Suche/de/nordrhein-westfalen/wohnung-kaufen"
    
    api_headers = {
        'accept': 'application/json; charset=utf-8',
        'accept-encoding': 'gzip, deflate, br',
        'accept-language': 'en-US,en;q=0.9',
        'x-requested-with': 'XMLHttpRequest',
        'referer': base_url,
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36',
    }

    params = {
        'price': '1000.0-',
        'constructionyear': '-2000',
        'pagenumber': '1'
    }

    def start_requests(self):
        # 首次访问基础页获取合法cookie
        yield scrapy.Request(
            url=self.base_url,
            headers={
                'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
                'user-agent': self.api_headers['user-agent'],
                'accept-language': self.api_headers['accept-language']
            },
            callback=self.request_search_api
        )

    def request_search_api(self, response):
        # cookie已自动保存,再请求带参数的JSON接口
        req_url = f'{self.base_url}?{urllib.parse.urlencode(self.params)}'
        yield scrapy.Request(
            url=req_url,
            headers=self.api_headers,
            callback=self.parse,
        )

    def parse(self,response):
        # 校验响应格式,避免解析报错
        if 'application/json' not in response.headers.get('Content-Type', b'').decode():
            self.logger.warning("Intercepted by anti-crawl, retrying...")
            # 触发重试,重新获取cookie
            yield scrapy.Request(
                url=self.base_url,
                headers={
                    'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
                    'user-agent': self.api_headers['user-agent'],
                    'accept-language': self.api_headers['accept-language']
                },
                callback=self.request_search_api,
                dont_filter=True
            )
            return
        yield {"response":response.json()}

requests版本

import requests

base_link = 'https://www.immobilienscout24.de/Suche/de/nordrhein-westfalen/wohnung-kaufen'

headers = {
    'accept': 'application/json; charset=utf-8',
    'accept-encoding': 'gzip, deflate, br',
    'accept-language': 'en-US,en;q=0.9',
    'x-requested-with': 'XMLHttpRequest',
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36',
    'referer': base_link,
}

params = {
        'price': '1000.0-',
        'constructionyear': '-2000',
        'pagenumber': '2'
}

sess = requests.Session()
# 第一步访问基础页获取初始cookie
sess.get(
    base_link,
    headers={
        'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
        'user-agent': headers['user-agent'],
        'accept-language': headers['accept-language']
    }
)
# 再请求带参数的搜索接口
resp = sess.get(base_link, params=params, headers=headers)
# 校验响应格式后再解析
if 'application/json' in resp.headers.get('Content-Type', ''):
    print(resp.json())
else:
    print(f"Request blocked, status code: {resp.status_code}")

补充说明

不要硬编码固定cookie,站点的会话cookie有有效期,过期后即使携带也会被拦截;如果遇到验证码拦截,不要重复发送接口请求,先重新访问基础页刷新cookie后再重试。

内容的提问来源于stack exchange,提问作者robots.txt

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 08:39:09