【问题标题】:Dealing with multiple encoding schemes while downloading the XML feed在下载 XML 提要时处理多种编码方案
【发布时间】:2017-11-23 13:52:58
【问题描述】:

我正在尝试阅读以下 URL 的提要:

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);
});

有没有一种方法可以让我获得数据而不管它的编码是什么?我应该如何处理?

【问题讨论】:

    标签: javascript node.js xml encoding httprequest


    【解决方案1】:

    您错过了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称,只有

    • 'ascii' - 仅适用于 7 位 ASCII 数据。这种编码速度很快,如果设置了会去掉高位。

    • 'utf8' - 多字节编码的 Unicode 字符。许多网页和其他文档格式使用 UTF-8。

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

    • 'ucs2' - 'utf16le' 的别名。

    • 'base64' - Base64 编码。从字符串创建缓冲区时,此编码还将正确接受 RFC4648 第 5 节中指定的“URL 和文件名安全字母”。

    • 'latin1' - 一种将 Buffer 编码为单字节编码字符串的方法(由 IANA 在 RFC1345 第 63 页中定义,作为 Latin-1 补充块和 C0/C1 控制代码)。

    • 'binary' - 'latin1' 的别名。

    • 'hex' - 将每个字节编码为两个十六进制字符。

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

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

    【讨论】:

      【解决方案2】:

      棘手的部分是将编码作为 null 传递来获取 Buffer 而不是字符串。

      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);
      });
      

      再次,在后续问题的上下文中,“
      有什么方法可以检测编码吗?”

      我希望你所说的“检测”是指找到声明。 (……而不是猜测。如果您必须猜测,那么您的通信失败。)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); 
      });
      

      【讨论】:

      • 有没有办法检测编码?脚本需要解析许多页面,并且它们都可能具有不同的编码方案。所以,我永远不会提前知道编码
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多