在python 3中处理多个字符集

时间:2012-10-26 14:44:59

标签: python character-encoding python-3.3

我在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,该怎么办?意味着我可能有不同的网站网址与不同的字符集。 那么,如何处理多个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文档中,但仍然没有运气,或者我可能没有选择正确的模块/内容来阅读!

4 个答案:

答案 0 :(得分:5)

在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)并让它们处理确定编码。他们经常为文档类型实现正确的charset-sniffing算法。
  3. 如果这些都不起作用,您可以更积极地使用像chardet这样的库来检测编码,但根据我的经验,错误地为其网页提供服务的人是如此无能,以至于他们生成混合编码文档,无论你做什么,你都会得到垃圾字符!

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

    1. 没有明确的charset声明:
      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. 否则使用宣称的字符集。
    3. (请注意,html5规范通过查找优先于 Content-Type标头的UTF8和UTF16字节标记来故意违反w3c规范。请阅读该编码检测算法链接,看看为什么我们可以没有好东西......)

答案 1 :(得分:2)

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

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

答案 2 :(得分:1)

您正在检查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

答案 3 :(得分:1)

查看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 =”并提取值。