【问题标题】:dealing with multiple charset in python 3在 python 3 中处理多个字符集
【发布时间】:2012-10-26 14:44:58
【问题描述】:

我在 Windows 8 中使用 python 3.3.0。

requrl = urllib.request.Request(url) 

response = urllib.request.urlopen(requrl)

source = response.read()

source = source.decode('utf-8')

如果网站有utf-8 字符集,它会正常工作,但如果它有iso-8859-1 或任何其他charset 怎么办。意味着我可能有不同的网站网址和不同的字符集。 那么,如何处理多个字符集呢?

现在让我告诉您我尝试解决此问题时的努力,例如:

    b1 = b'charset=iso-8859-1'
    b1 = b1.decode('iso-8859-1')

    if b1 in source:
            source = source.decode('iso-8859-1')

它给了我一个像TypeError: Type str doesn't support the buffer API这样的错误 所以,我假设它将 b1 视为字符串!这不是正确的方法! :(

请不要说手动更改源代码中的字符集或您阅读过python文档! 我已经尝试过深入研究 python 3 文档,但仍然没有运气,或者我可能没有选择正确的模块/内容来阅读!

【问题讨论】:

  • 通过删除你的问题的一部分,你把我的回答变成了一个疯子的漫无边际。

标签: python character-encoding python-3.3


【解决方案1】:

在 Python 3 中,str 实际上是一个 unicode 字符序列(相当于 Python 2 中的 u'mystring' 语法)。你从response.read() 得到的是一个字节串(一个字节序列)。

b1 in source 失败的原因是您试图在 字节字符串 中查找 unicode 字符序列。这是没有意义的,所以它失败了。如果您取出b1.decode('iso-8859-1') 行,它应该可以工作,因为您现在正在比较两个字节序列。

现在回到您真正的根本问题。 要支持多个字符集,您需要确定字符集,以便将其解码为 Unicode 字符串。这很难做到。通常,您可以检查响应的 Content-Type 标头。 (请参阅下面的规则。)但是,许多网站在标题中声明了错误的编码,我们不得不开发其他 complicated encoding sniffing rules for html。请阅读该链接,以便您了解这是一个多么困难的问题!

我推荐你:

  1. 使用 requests 库而不是 urllib,因为它会自动正确处理大多数 unicode 转换。 (它也更容易使用。)如果在这一层转换为 unicode 失败:
  2. 尝试将字节直接传递给您正在使用的底层库(例如lxmlhtml5lib)并让它们处理确定编码。他们通常为文档类型实施正确的字符集嗅探算法。

如果这些都不起作用,您可以更积极地使用 chardet 之类的库来检测编码,但根据我的经验,错误地提供网页服务的人非常无能,以至于他们产生了混合编码的文档,所以不管你做什么,你最终都会得到垃圾字符!

以下是解释content-type 标头中声明的字符集的规则。

  1. 没有明确声明的字符集:
    1. text/*(例如 text/html)是 ASCII 格式。
    2. application/*(例如 application/json、application/xhtml+xml)是 utf-8。
  2. 声明了明确的字符集:
    1. 如果 type 是 text/html 并且 charset 是 iso-8859-1,它实际上是 win-1252 (==CP1252)
    2. 否则使用声明的字符集。

(请注意,html5 规范通过查找 UTF8 和 UTF16 字节标记优先于 Content-Type 标头来故意违反 w3c 规范。请阅读该编码检测算法链接,看看为什么我们可以'没有好东西...)

【讨论】:

  • 应用程序/*的有趣预设。你有那个来源吗?
  • 我会说application/*在很多情况下不是utf8,如快速grep from /etc/apache2/magic所示
【解决方案2】:

这里的大问题是,在许多情况下,您无法确定网页的编码,即使它定义了一个字符集。我已经看到足够多的页面声明一个字符集但实际上在另一个,或者在其 Content-Type 标头中具有不同的字符集,然后在其元标记或 xml 声明中。

在这种情况下,chardet 会有所帮助。

【讨论】:

  • 嗯,如果他们这样做,那可能是个大问题。我可以很好地理解它。那么,我必须使用该 chardet 还是在 python 中有什么方法可以自动检测/获取字符集?无论如何,哪些字符集最常用于网站?否则我的脚本将仅限于 utf-8 编码! :(
  • chardet 尝试通过查看已知字符序列并应用不同的启发式方法来确定文本的字符集,因此如果页面没有声明字符集或错误的字符集,它可以为您提供帮助,当然您在这种情况下可以编写自己的逻辑来检测字符集,但为什么要重新发明轮子(例如请求也使用 chardet)。当然,在大多数情况下,页面声明的字符集是正确的,但是有一个后备方法来确定字符集不会有什么坏处。有关最常用字符集的信息,请查看here
  • OMG,看了那个链接后,我必须说,我会尝试使用 utf-8 或 iso-8859-1
【解决方案3】:

您正在检查 str 字节是否包含在 bytes 对象中:

>>> 'df' in b'df'
Traceback (most recent call last):
  File "<pyshell#107>", line 1, in <module>
    'df' in b'df'
TypeError: Type str doesn't support the buffer API

所以,是的,它认为b1str,因为您已将bytes 对象解码为具有特定编码的str 对象。相反,您应该检查 b1 的原始值。不清楚你为什么对它做.decode

【讨论】:

  • 嘿,你可能是对的,但这不是我的实际问题。我试图得到结果。但是你让我清楚地知道它实际上做了什么以及它为什么会出错。我的问题是关于差异的支持。字符集
  • @magneto:你的问题是什么?
  • 我已经编辑了我上面的评论。现在,你有我的问题。关于字符集???否则请给我您的电子邮件 ID,以便我们就此进行辩论。 :) 这真是一个大问题。如果我没记错的话,在 python 3 中!
  • @magneto: 你可以试试requests 包吗?他们宣传 unicode 响应机构。这似乎是你想要的。否则,像您所做的那样检测字符集并对其进行解码可能是前进的方向。
  • @magneto:如果它工作正常,那就不是问题了。无论如何,最简单的方法就是您正在做的事情:检查提供的字符集(如果有,可能会丢失)并尝试以该编码解码页面(如果它在 python 中可用)。同样,这是一种容易出错的方法,最好使用现有的库。 StackOverflow 的重点是我们正在进行公开讨论,以便其他人可以找到它并从中学习。这不应该是一个讨论,当然,更多的是一个问答,但我看不出还能说什么,你现在已经如何检查字符集和解码
【解决方案4】:

看看HTML standard, Parsing HTML documents, Determine character set(HTML5 足以满足我们的目的)。

有一个算法可以采用。 您的目的归结为以下几点:

  1. 检查 UTF-16 或 UTF-8 的识别序列(请参阅提供的链接)
  2. 使用 HTTP 提供的字符集(通过Content-Type header
  3. 应用稍后在Prescan a byte-stream to determine its encoding 中描述的算法。这基本上是在文档中搜索“charset=”并提取值。

【讨论】:

    猜你喜欢
    • 2020-05-07
    • 1970-01-01
    • 1970-01-01
    • 2016-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-13
    • 1970-01-01
    相关资源
    最近更新 更多