jsondecodeerror总在response.text上直接json.loads()时爆发,因response.text可能是空字符串、html错误页、重定向提示或非json二进制内容;务必先检查status_code是否为200,再校验content-type及响应内容。

JSONDecodeError 为什么总在 response.text 上直接 json.loads() 时爆发
因为 response.text 可能是空字符串、HTML 错误页(比如 404 页面)、重定向提示,或者服务端返回了非 JSON 的二进制内容(如图片)。直接 json.loads(response.text) 会立刻抛出 JSONDecodeError,且错误信息里只说“Expecting value”,根本看不出原始响应长啥样。
- 务必先检查
response.status_code是否为 200(或你预期的成功码),再考虑解析 - 用
response.content而不是response.text做初步判断:如果开头是b'{'或b'[',才大概率是 JSON;如果是b',就别硬 parse - 捕获异常时,把
response.text[:200]和response.status_code一起打出来,比只看 traceback 实用得多
requests.get() 后怎么安全地提取 JSON 数据
response.json() 看似方便,但它内部还是调用 json.loads(),同样会炸。真正的安全做法是封装一层带状态和内容校验的解析逻辑:
def safe_json_from_response(resp):
if not resp.ok:
return None, f"HTTP {resp.status_code}"
try:
# 先尝试用 requests 自带的 json(),它会检查 Content-Type
return resp.json(), None
except ValueError as e: # 注意:requests 1.x 用 ValueError,2.x 改成 JSONDecodeError
content_type = resp.headers.get("Content-Type", "")
if "application/json" not in content_type.lower():
return None, f"Non-JSON Content-Type: {content_type}"
return None, f"Invalid JSON: {str(e)[:100]} - Raw preview: {resp.text[:150]}"
- 不要依赖
Content-Type100% 准确——有些接口乱设为text/plain却返回 JSON - 若业务允许容忍部分字段缺失,可用
json.loads(resp.text, strict=False)(Python 3.11+),但慎用,它可能掩盖编码问题 - 对 POST 接口,还要注意
response.encoding是否被 requests 自动猜错,导致中文变乱码再引发解析失败
遇到 UnicodeDecodeError 怎么定位是不是编码惹的祸
常见报错:UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0。这通常不是 JSON 问题,而是响应体本身不是 UTF-8 编码,但 requests 错误地按 UTF-8 解码了 response.text。
图片提示词生成器?不止如此。 马甲系统 —— 把脑海中的画面,翻译成AI能理解的专业表达。 用得越多,它越懂你:首次需要多问几句确认方向,用久了几乎一说就懂。 用得越多,它越快:缓存机制让后续对话越来越省。 RAG进化:成功案例持续入库,越跑越聪明。 输入「新手指南」查看完整功能介绍
- 优先用
response.content(bytes)传给json.loads(),并显式指定encoding:json.loads(resp.content, encoding="gbk") - 查真实编码:用
chardet.detect(resp.content)看推荐编码,但别无脑信——某些小众接口返回的 GBK 内容里混了 UTF-8 BOM,chardet会误判 - 最稳的方式:先
resp.content.decode("utf-8", errors="ignore")得到可读文本,再检查是否含{或[,否则跳过解析
异步爬虫(aiohttp)里 JSON 解析失败怎么不卡住整个协程
aiohttp.ClientResponse.json() 是个 awaitable,但它一旦失败就会抛异常中断当前 task。没做 try/except 就等于把整个并发请求流挂掉。
- 必须每个
await resp.json()都包在独立的try/except里,不能只在外层 catch - 别用
asyncio.gather()直接扔一堆fetch_and_parse()进去——一个失败,全部 cancel。改用asyncio.create_task()+ 单独 await 每个 task - 注意
aiohttp默认不校验Content-Type,所以即使响应头写着text/html,.json()仍会尝试解析,照样崩
实际跑起来你会发现,90% 的 JSON 解析异常背后都不是 JSON 格式本身的问题,而是 HTTP 层没稳住——状态码、编码、Content-Type、网络截断,这些环节漏检一个,json.loads 就得背锅。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










