- 工信部備案號 滇ICP備05000110號-1
- 滇公安備案 滇53010302000111
- 增值電信業(yè)務(wù)經(jīng)營許可證 B1.B2-20181647、滇B1.B2-20190004
- 云南互聯(lián)網(wǎng)協(xié)會理事單位
- 安全聯(lián)盟認(rèn)證網(wǎng)站身份V標(biāo)記
- 域名注冊服務(wù)機構(gòu)許可:滇D3-20230001
- 代理域名注冊服務(wù)機構(gòu):新網(wǎng)數(shù)碼
在 Node 層利用 cheerio 解析網(wǎng)頁時,輸出的中文內(nèi)容都是以 &#x 開頭的一堆像亂碼一樣的東西,嘗試過各種編碼都無效,而且神奇的是,將這一堆“亂碼”保存成網(wǎng)頁后,通過瀏覽器打開又可以正常顯示。這到底是什么????
縮減后的示例代碼如下:
const cheerio = require(‘cheerio‘); const $ = cheerio.load(‘<div id="content">你好</div>‘) console.log($(‘#content‘).html()) //你好
其實,上面那一堆亂碼一樣的東西,它的學(xué)名叫實體編碼 entity code。
下面引用下知乎搜到的答案。
在 HTML 中,某些字符是預(yù)留的,例如小于號「<」、大于號「>」等,瀏覽器會將它們視作標(biāo)簽。如果想要在HTML中顯示這些預(yù)留字符,我們就要用到字符實體(character entities)。我們比較熟悉的字符實體有空格「 」,小于號「<」,大于號「>」等。這樣的格式比較語義化,容易記憶,但其實字符實體有其他的格式:
&name;&#dddd;&#xhhhh;
這三種轉(zhuǎn)義方式都稱作 character reference,第一種是 character entity reference,「&」符號后接預(yù)先定義好的 entity 名稱。
后兩種是 numeric character reference,數(shù)字取值為目標(biāo)字符的 Unicode code point;以「&#」開頭的后接十進制數(shù)字,「&#x」開頭的后接十六進制數(shù)字。
從 HTML4 開始,numeric character reference 以 Unicode 為準(zhǔn),與文檔編碼無關(guān)?!改愫谩苟址謩e是 Unicode 字符 U+4F60 和 U+597D,十六進制表示的 code point 數(shù)值「4F60」和「597D」,同時也就是十進制的「20320」和「22909」。所以
在HTML中輸入
你好你好
都會顯示為“你好”。
知道原因后,那么如何解決上述的問題呢?
方法一:使用cheerio提供的屬性
cheerio默認(rèn)會對entity進行decode,我們只需要關(guān)閉該功能即可
const cheerio = require(‘cheerio‘); const $ = cheerio.load(‘<div id="content">你好</div>‘, { decodeEntities: false }) console.log($(‘#content‘).html()) // 你好
方法二:手動decode
function decode(str) { // 一般可以先轉(zhuǎn)換為標(biāo)準(zhǔn) unicode 格式(有需要就添加:當(dāng)返回的數(shù)據(jù)呈現(xiàn)太多\\\u 之類的時) str = unescape(str.replace(/\\u/g, "%u")); // 再對實體符進行轉(zhuǎn)義 // 有 x 則表示是16進制,$1 就是匹配是否有 x,$2 就是匹配出的第二個括號捕獲到的內(nèi)容,將 $2 以對應(yīng)進制表示轉(zhuǎn)換 str = str.replace(/&#(x)?(\w+);/g, function($, $1, $2) { return String.fromCharCode(parseInt($2, $1? 16: 10)); }); return str; }
售前咨詢
售后咨詢
備案咨詢
二維碼
TOP