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

使用DOMXpath提取LD-Json后出现UTF-8二次编码问题求助

双重UTF-8编码问题:DOMDocument导致的字符乱码根源

这个问题我之前踩过坑!你遇到的其实是双重UTF-8编码问题,核心原因是DOMDocument::loadHTML的默认编码行为在搞鬼:

为什么编码会变?

当你用curl获取到的页面是标准UTF-8编码(比如“ół”的十六进制是C3 B3 C5 82),但DOMDocument::loadHTML默认会把输入内容当作**ISO-8859-1(Latin-1)**来解析。

这就导致了:

  1. UTF-8的每个字节被错误识别成一个独立的Latin-1字符
  2. 当你通过nodeValue提取内容时,这些Latin-1字符又被重新编码成UTF-8
  3. 最终就出现了双重编码的结果:C3 83 C2 B3 C3 85 C2 82(相当于把原来的UTF-8字节再转了一次UTF-8)

解决方法:明确告诉DOMDocument使用UTF-8编码

你只需要在加载HTML前,明确指定编码规则,就能解决这个问题。这里有两种可靠的方案:

方案1:使用libxml设置内部编码

直接告诉libxml库用UTF-8解析内容,代码修改如下:

$handle = curl_init();
curl_setopt($handle, CURLOPT_URL, $url);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
curl_setopt($handle, CURLOPT_FOLLOWLOCATION, true);
$page = curl_exec($handle);
curl_close($handle);

// 关键步骤:设置libxml内部编码为UTF-8
libxml_set_internal_encoding('UTF-8');

$dom = new DOMDocument();
// 用LIBXML_NOERROR替代@符号,更优雅地抑制解析警告
$dom->loadHTML($page, LIBXML_NOERROR | LIBXML_NOWARNING);
$xpath = new DOMXpath($dom);
$jsonScripts = $xpath->query('//script[@type="application/ld+json"]');

foreach ($jsonScripts as $jScript) {
    $json = $jScript->nodeValue;
    // 现在$json是正确的UTF-8编码,json_decode可以正常处理
    $data = json_decode($json, true);
    // 后续业务逻辑...
}

方案2:手动添加UTF-8 Meta标签

如果方案1在你的PHP版本中不生效(比如某些旧版libxml),可以在页面内容开头插入一个UTF-8的meta标签,强制DOMDocument识别编码:

$handle = curl_init();
curl_setopt($handle, CURLOPT_URL, $url);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
curl_setopt($handle, CURLOPT_FOLLOWLOCATION, true);
$page = curl_exec($handle);
curl_close($handle);

// 在页面开头插入UTF-8编码声明
$page = '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">' . $page;

$dom = new DOMDocument();
$dom->loadHTML($page, LIBXML_NOERROR | LIBXML_NOWARNING);
$xpath = new DOMXpath($dom);
$jsonScripts = $xpath->query('//script[@type="application/ld+json"]');

foreach ($jsonScripts as $jScript) {
    $json = $jScript->nodeValue;
    $data = json_decode($json, true);
    // 后续业务逻辑...
}

验证效果

修改后,再次提取“ół”字符,它的十六进制应该会回到正确的C3 B3 C5 82,json_decode也能正常解析LD-JSON内容了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 12:02:33