PHP cURL抓取不同日文站点出现UTF-8编码异常的通用方案问询
PHP cURL采集多站点编码兼容通用解决方案
问题根因
两个日本站点分别使用了不同的编码规则,站点1为标准UTF-8编码,站点2为日文场景常用的Shift_JIS/EUC-JP编码。原有方案的缺陷如下:
mb_detect_encoding默认未开启严格检测,且检测列表未覆盖日文常用编码,容易将非UTF-8编码误判为UTF-8utf8_decode仅支持UTF-8转ISO-8859-1编码,仅适用于西欧字符场景,完全不匹配日文编码转换需求
通用处理方案
按照「HTTP响应头声明编码 > HTML页面meta标签声明编码 > 严格模式自动检测」的优先级获取原始编码,再统一转换为目标编码(推荐统一转UTF-8),具体实现代码如下:
$ua= "Mozilla/5.0 (X11; Linux i686; rv:36.0) Gecko/20100101 Firefox/36.0 SeaMonkey/2.33.1"; $options = array( CURLOPT_RETURNTRANSFER => true, CURLOPT_FAILONERROR => true, CURLOPT_FOLLOWLOCATION => true, CURLOPT_ENCODING => "", CURLOPT_USERAGENT => $ua, CURLOPT_AUTOREFERER => true, CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_TIMEOUT => 10, CURLOPT_MAXREDIRS => 5, CURLOPT_FORBID_REUSE => true ); $ch = curl_init($url); curl_setopt_array($ch, $options); $content = curl_exec($ch); // 编码转换逻辑开始 $originCharset = null; // 优先级1:从HTTP响应头Content-Type字段提取编码 $contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE); if (preg_match('/charset=([a-zA-Z0-9_-]+)/i', $contentType, $matches)) { $originCharset = strtoupper(trim($matches[1])); } // 优先级2:从HTML meta标签提取编码 if (!$originCharset) { // 匹配HTML5标准meta charset声明 if (preg_match('/<meta\s+charset=["\']?([a-zA-Z0-9_-]+)["\']?/i', $content, $matches)) { $originCharset = strtoupper(trim($matches[1])); } // 匹配旧版Content-Type meta声明 elseif (preg_match('/<meta\s+http-equiv=["\']Content-Type["\']\s+content=["\'].*?charset=([a-zA-Z0-9_-]+)["\']?/i', $content, $matches)) { $originCharset = strtoupper(trim($matches[1])); } } // 优先级3:严格模式自动检测编码,可根据采集站点区域调整检测列表 if (!$originCharset) { // 日文站点检测列表,中文站可替换为['UTF-8', 'GBK', 'GB2312', 'BIG5'] $detectList = ['UTF-8', 'SHIFT-JIS', 'EUC-JP', 'ISO-8859-1']; $originCharset = mb_detect_encoding($content, $detectList, true); } // 统一转换为UTF-8编码 if ($originCharset && $originCharset !== 'UTF-8') { $content = mb_convert_encoding($content, 'UTF-8', $originCharset); } curl_close($ch); // 转码完成后再做HTML解析 $html = str_get_html($content);
注意事项
- 可根据采集站点的所属区域调整自动检测的编码列表,进一步提升检测准确率
- 必须在HTML解析前完成全量内容转码,不要对解析后的DOM节点文本单独转码,避免解析阶段就出现字符丢失
内容的提问来源于stack exchange,提问作者ErickBest
相关产品推荐
相关产品推荐

