在 Node 层利用cheerio解析网页时,输出的中文内容都是以&#x开头的一堆像乱码一样的东西,尝试过各种编码都无效,而且神奇的是,将这一堆“乱码”保存成网页后,通过浏览器打开又可以正常显示。这到底是什么????
缩减后的示例代码如下:
constcheerio=require(‘cheerio‘);
const$=cheerio.load(‘<divid=\"content\">你好</div>‘) console.log($(‘#content‘).html())//你好其实,上面那一堆乱码一样的东西,它的学名叫实体编码 entity code。
下面引用下知乎搜到的答案。
在 HTML 中,某些字符是预留的,例如小于号「<」、大于号「>」等,浏览器会将它们视作标签。如果想要在HTML中显示这些预留字符,我们就要用到字符实体(character entities)。我们比较熟悉的字符实体有空格「 」,小于号「<」,大于号「>」等。这样的格式比较语义化,容易记忆,但其实字符实体有其他的格式:
&name;&#dddd;&#xhhhh;
这三种转义方式都称作 character reference,第一种是 character entity reference,「&」符号后接预先定义好的 entity 名称。
后两种是 numeric character reference,数字取值为目标字符的 Unicode code point;以「&#」开头的后接十进制数字,「&#x」开头的后接十六进制数字。
从 HTML4 开始,numeric character reference 以 Unicode 为准,与文档编码无关。「你好」二字分别是 Unicode 字符 U+4F60 和 U+597D,十六进制表示的 code point 数值「4F60」和「597D」,同时也就是十进制的「20320」和「22909」。所以
在HTML中输入
你好你好都会显示为“你好”。
知道原因后,那么如何解决上述的问题呢?
方法一:使用cheerio提供的属性
cheerio默认会对entity进行decode,我们只需要关闭该功能即可
constcheerio=require(‘cheerio‘); const$=cheerio.load(‘<divid=\"content\">你好</div>‘,{decodeEntities:false}) console.log($(‘#content‘).html())//你好方法二:手动decode
functiondecode(str){//一般可以先转换为标准unicode格式(有需要就添加:当返回的数据呈现太多\\\\\\u之类的时) str=unescape(str.replace(/\\\\u/g,\"%u\"));//再对实体符进行转义 //有x则表示是16进制,$1就是匹配是否有x,$2就是匹配出的第二个括号捕获到的内容,将$2以对应进制表示转换 str=str.replace(/&#(x)?(\\w+);/g,function($,$1,$2){returnString.fromCharCode(parseInt($2,$1?16:10)); });returnstr; }附:在线Html实体编码/解码网址:https://config.net.cn/tools/HtmlEncode.html
