如何正确解析被 HTML 实体编码的嵌套 JSON 字段
技术百科
碧海醫心
发布时间:2026-01-27
浏览: 次 当 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() 直接识别。
✅ 正确处理流程如下:
- 先解析顶层 JSON:使用 response.json() 或 json.loads(response.content) 获取主数据结构;
- 定位被编码的字段:如 r["child_sku_options"](类型为 str);
- HTML 解码:调用 html.unescape() 消除 "、/、\/ 等转义,还原为标准 JSON 字符串;
- 二次 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 等平台返回的嵌套结构化商品选项数据,彻底告别 \/ 和 " 带来的解析困扰。
# ai
# 搜索结果
# 就能
# 是一个
# 这一
# 它会
# python
# safari
# windows
# 而非
# app
# 数据结构
# win
# js
# json
# go
# 对象
# html
# 编码
# xml
# 字符串
# 报错
# bom
# ssl
# 遍历
# print
# ajax
# 原为
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- 怎么将XML数据可视化 D3.js加载XML
- Win11怎么关闭键盘按键音_Win11禁用打字声
- 如何在同包不同文件中正确引用 Go 结构体
- 如何使用Golang反射将map转换为struct
- Windows10电脑怎么设置文件权限_Win10
- Win11怎么更改系统语言为中文_Windows1
- PhpStorm怎么调试PHP代码_PhpStor
- Windows10电脑怎么连接蓝牙设备_Win10
- 如何在 Pandas 中按元素交集合并两列字符串
- Python数据挖掘进阶教程_分类回归与聚类案例解
- C#如何序列化对象为XML XmlSerializ
- c++23 std::expected怎么用 c+
- Mac怎么设置登录项_Mac管理开机自启动程序【教
- PHP主流架构如何处理会话管理_Session与C
- Win11怎么关闭搜索历史_Win11清除任务栏搜
- 静态属性修改会影响所有实例吗_php作用域操作符下
- Win11时间格式怎么改成12小时制 Win11时
- C++如何使用std::optional?(处理可
- Go 语言标准库为何不提供泛型切片的 Contai
- Python多进程教程_multiprocessi
- Mac如何备份到iCloud_Mac桌面与文稿文件
- Win11怎么更改系统语言_Win11中文语言包下
- Windows蓝屏错误0x0000002C怎么解决
- c++ unordered_map怎么用 c++哈
- 如何在Golang中定义接口_抽象方法和多态实现
- Win11如何更新显卡驱动 Win11检查和安装设
- c++怎么实现大文件的分块读写_c++ 文件指针s
- Python函数缓存机制_lru_cache解析【
- Win11怎么设置快速访问_Windows11文件
- 如何自定义Windows终端的默认配置文件?(Po
- Python对象生命周期管理_创建销毁解析【教程】
- Win10怎样清理C盘爱奇艺缓存_Win10清理爱
- win11 OneDrive怎么彻底关闭 Win1
- Python随机数生成_random模块说明【指导
- Win11关机快捷键是什么_Win11快速关机方法
- 如何使用Golang实现跨域请求支持_Golang
- 如何使用Golang实现函数指针_函数变量与回调示
- Golang如何避免指针逃逸_Golang逃逸分析
- Win11怎么用设置清理回收站_Win11设置清理
- Win10系统怎么查看网络连接状态_Windows
- 本地php环境出现502错误_nginx或apac
- php能跑在stm32上吗_php在stm32微控
- c++如何实现多态性_c++ 虚函数表原理与动态绑
- c++协程和线程的区别 c++异步编程模型对比【核
- PyTorch DDP 多进程训练在 Kaggle
- PHP主流架构怎么处理表单验证_规则与自定义【技巧
- Win10如何卸载自带Edge_Win10彻底卸载
- Python多线程使用规范_线程安全解析【教程】
- Python并发安全问题_资源竞争说明【指导】
- Win11怎么开启专注模式_Windows11时钟


QQ客服