如何正确解析被 HTML 实体编码的嵌套 JSON 字段

9次阅读

如何正确解析被 HTML 实体编码的嵌套 JSON 字段

当 api 返回的 json 中某些字段(如 `child_sku_options`)实际是经过 html 实体编码json 字符串时,直接 `json.loads()` 会失败;需先用 `html.unescape()` 还原转义字符,再二次解析。

在调用某些搜索服务(如 SearchSpring)的 API 时,常见一种“伪嵌套 json”现象:主响应是合法 JSON,但其中某个字符串字段(例如 “child_sku_options”)的值并非原始 JSON 对象,而是被双重编码的 JSON 字符串——它被 HTML 实体转义(如 / 代替 /、” 替代 “),导致直接解析报错或输出乱码。

你的原始代码:

print(json.loads(response.content))

看似合理,但问题出在 response.content 解析后得到的 data[“results”][i][“child_sku_options”] 是一个字符串形式的、被 HTML 转义的 JSON,例如:

"{"option_value_id":197674,"value":"12 Degree",..."image_url":"https:\/\/cdn11.bigcommerce.com\/...jpg"}"

该字符串中的 / 和 ” 是 HTML/xml 编码结果,并非标准 JSON 允许的原始反斜杠,因此无法被 json.loads() 直接识别。

立即学习前端免费学习笔记(深入)”;

✅ 正确处理流程如下:

  1. 先解析顶层 JSON:使用 response.json() 或 json.loads(response.content) 获取主数据结构
  2. 定位被编码的字段:如 r[“child_sku_options”](类型为 str);
  3. HTML 解码:调用 html.unescape() 消除 “、/、/ 等转义,还原为标准 JSON 字符串;
  4. 二次 JSON 解析:对解码后的字符串执行 json.loads(),得到真正的 python 字典/列表。

以下是完整、健壮的示例代码(含错误处理和推荐实践):

import json import requests from html import unescape  url = "https://547os1.a.searchspring.io/api/search/search.json?ajaxCatalog=v3&resultsFormat=native&siteId=547os1&domain=https%3A%2F%2Fwww.golfbox.com.au%2Fsearch%3Fq%3DCalaway%2BParadym%2BDriver%26Search%3DSEARCH&q=Calaway%20Paradym%20Driver"  headers = {     "User-Agent": "Mozilla/5.0 (windows NT 10.0; Win64; x64) appleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 safari/537.36" }  try:     response = requests.get(url, headers=headers, timeout=10, verify=False)     response.raise_for_status()  # 检查 HTTP 错误状态码      # 解析顶层 JSON     data = response.json()      # 遍历搜索结果,提取并解析 child_sku_options     for i, result in enumerate(data.get("results", [])):         options_str = result.get("child_sku_options")         if not isinstance(options_str, str) or not options_str.strip():             print(f"[跳过] 第 {i+1} 条结果无 child_sku_options 字段")             continue          try:             # 步骤1:HTML 解码 → 还原为标准 JSON 字符串             decoded_str = unescape(options_str)             # 步骤2:JSON 解析 → 转为 Python 对象             options_list = json.loads(decoded_str)             print(f"✅ 第 {i+1} 条结果解析成功,共 {len(options_list)} 个 SKU 选项:")             # 示例:打印首个选项的 child_sku 和 price             if options_list:                 first = options_list[0]                 print(f"   - SKU: {first.get('child_sku', 'N/A')}, Price: ${first.get('price', 'N/A')}")         except json.JSONDecodeError as e:             print(f"❌ 解析第 {i+1} 条的 child_sku_options 失败:{e}")             print(f"   原始字符串(截取前100字符):{options_str[:100]}...")         except Exception as e:             print(f"⚠️  其他异常:{e}")  except requests.exceptions.RequestException as e:     print(f"网络请求失败:{e}") except json.JSONDecodeError as e:     print(f"顶层 JSON 解析失败:{e}")

? 关键注意事项:

  • ❌ 不要禁用 ssl 验证(verify=False)用于生产环境——它会带来安全风险。如遇证书问题,请更新 CA 证书或使用 requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS 调整 TLS 设置,而非关闭验证。
  • ✅ 优先使用 response.json() 而非 json.loads(response.content),前者自动处理编码(如 UTF-8 bom、Content-Type charset),更可靠。
  • ✅ 始终校验字段是否存在(dict.get())、类型是否正确(isinstance(…, str)),避免 KeyError 或 TypeError。
  • ? 若发现 unescape() 后仍解析失败,可用 print(repr(decoded_str)) 查看真实字符串内容,确认是否含不可见控制字符(如 u2028 行分隔符),必要时用正则清洗。

通过这一“HTML 解码 + 二次 JSON 解析”的组合策略,你就能稳定提取 SearchSpring 等平台返回的嵌套结构化商品选项数据,彻底告别 / 和 ” 带来的解析困扰。

text=ZqhQzanResources