2

我在 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 文档中,但仍然没有运气,或者我可能没有选择正确的模块/内容来阅读!

4

4 回答 4

5

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

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

现在回到你真正的根本问题。要支持多个字符集,您需要确定字符集,以便将其解码为 Unicode 字符串。这很难做到。通常,您可以检查Content-Type响应的标头。(请参阅下面的规则。)但是,如此多的网站在标头中声明了错误的编码,我们不得不为 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 规范。请阅读编码检测算法链接,看看为什么我们不能有好的东西......)

于 2012-10-27T16:09:08.467 回答
2

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

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

于 2012-10-27T15:41:18.060 回答
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, 因为您已经将对象解码bytesstr具有特定编码的对象。相反,您应该检查b1. 目前尚不清楚你为什么这样做.decode

于 2012-10-26T14:52:30.533 回答
1

查看HTML 标准,解析 HTML 文档,确定字符集(HTML5 足以满足我们的目的)。

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

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