下载XML Feed时处理多种编码方案

时间:2017-11-23 13:52:59

标签: javascript node.js xml encoding httprequest

我正在尝试通过以下网址阅读Feed:

http://www.chinanews.com/rss/scroll-news.xml

使用request module。但我得到的内容有���� ʷ����)������(�й�)���޹�

在审核XML时,我发现编码设置为<?xml version="1.0" encoding="gb2312"?>

但是在尝试将编码设置为gb2312时,我得到了未知的编码错误。

request({
    url: "http://www.chinanews.com/rss/scroll-news.xml",
    method: "GET",
    headers: {
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "Accept-Encoding": "gzip, deflate",
        "Host": "www.chinanews.com",
        "Accept-Language": "en-GB,en-US;q=0.8,en;q=0.6"
    },
    "gzip": true,
    "encoding": "utf8"
}, (err, resp, data) => {
    console.log(data);
});

有没有一种方法可以获得数据而不管它有什么编码?我该怎么做呢?

2 个答案:

答案 0 :(得分:0)

你错过了character encoding的概念。

var iconv=require('iconv-lite'), request=require('request');
request({
    url: "http://www.chinanews.com/rss/scroll-news.xml",
    method: "GET",
    headers: {
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "Accept-Encoding": "gzip, deflate",
        "Host": "www.chinanews.com",
        "Accept-Language": "" // client accept language
    },
    gzip: true,
    encoding: null // or 'ascii'
}, (err, resp, body) => {
    console.log(iconv.decode(Buffer.from(body, 'ascii'), 'gb2312'));
});

chunk是node.js中的Buffer个实例。根据官方documention,只有

  
      
  • &#39; ASCII&#39; - 仅适用于7位ASCII数据。此编码速度很快,如果设置,将剥离高位。

  •   
  • &#39; UTF8&#39; - 多字节编码的Unicode字符。许多网页和其他文档格式使用UTF-8。

  •   
  • &#39; utf16le应按&#39; - 2或4个字节,little-endian编码的Unicode字符。支持代理对(U + 10000到U + 10FFFF)。

  •   
  • &#39; UCS2&#39; - 别名&#39; utf16le&#39;。

  •   
  • &#39; BASE64&#39; - Base64编码。从字符串创建缓冲区时,此编码也将正确接受&#34; URL和文件名安全字母&#34;如RFC4648第5节中所述。

  •   
  • &#39; LATIN1&#39; - 将缓冲区编码为单字节编码字符串的方法(由RFC1345中的IANA定义,第63页,为Latin-1补充块和C0 / C1控制代码)。

  •   
  • &#39;二进制&#39; - 别名为&#39; latin1&#39;。

  •   
  • &#39;十六进制&#39; - 将每个字节编码为两个十六进制字符。

  •   

node.js包含当前supported。要使用node.js不支持的编码natively,请使用iconviconv-liteother libraries来获取字符映射表。这与this answer非常相似。

Accept-Language表示客户接受的语言。 en-gb代表English (United Kingdom),但不代表中文。根据RFC 7231,中文版本为zh-cn, zh

答案 1 :(得分:0)

棘手的部分是将编码传递为null以获取缓冲区而不是字符串。

  

encoding - 用于响应数据的setEncoding的编码。   如果null,正文将以Buffer返回。

- request

var request = require('request');
var legacy = require('legacy-encoding');


var requestSettings = {
    method: 'GET',
    url: 'http://www.chinanews.com/rss/scroll-news.xml',
    encoding: null,
};

request(requestSettings, function(error, response, body) {    
    var text = legacy.decode(body, 'gb2312');    
    console.log(text);
});

同样,在后续问题的背景下,&#34;
有没有办法检测编码?&#34;

通过&#34;检测&#34;我希望你的意思是,找到声明。 (...而不是猜测。如果你必须猜测,那么你的通信失败。)HTTP响应头Content-Type是传递编码的主要方式(如果适用于MIME类型)。某些MIME类型允许在内容中声明编码,因为服务器非常正确地遵循它。

对于您的RSS回复。服务器发送Content-Type:text/xml。没有编码覆盖。内容的XML声明是<?xml version="1.0" encoding="gb2312"?> XML规范具有查找此类声明的过程。它基本上等于用不同的编码读取,直到XML声明变得易懂,然后用声明的编码重新读取。

var request = require('request');
var legacy = require('legacy-encoding');
var convert = require('xml-js');

// specials listed here: https://www.w3.org/Protocols/rfc1341/4_Content-Type.html
var charsetFromContentTypeRegex = (/charset=([^()<>@,;:\"/[\]?.=\s]*)/i).compile(); 

var requestSettings = {
    method: 'GET',
    url: 'http://www.chinanews.com/rss/scroll-news.xml',
    encoding: null,
};


request(requestSettings, function(error, response, body) {    
    var contentType = charsetFromContentTypeRegex.exec(response.headers['content-type'])
    var encodingFromHeader = contentType.length > 1 ? contentType[1] : null;

    var doc = convert.xml2js(body);
    var encoding = doc.declaration.attributes.encoding;
    doc = convert.xml2js(
        legacy.decode(body, encodingFromHeader ? encodingFromHeader : encoding));
    // xpath /rss/channel/title
    console.log(doc.elements[1].elements[0].elements[0].elements[0].text); 
});