【问题标题】:Requests module encoding provides different encode then HTML encode请求模块编码提供与 HTML 编码不同的编码
【发布时间】:2016-04-06 13:57:40
【问题描述】:

请求模块encoding提供的编码与HTML页面中实际设置的编码不同

代码:

import requests
URL = "http://www.reynamining.com/nuevositio/contacto.html"
obj = requests.get(URL, timeout=60, verify=False, allow_redirects=True)
print obj.encoding

输出:

ISO-8859-1

HTML 中设置的实际编码是 UTF-8 content="text/html; charset=UTF-8"

我的问题是:

  1. 为什么requests.encoding 显示的编码与 HTML 页面中描述的编码不同?。

我正在尝试使用此方法 objReq.content.decode(encodes).encode("utf-8") 将编码转换为 UTF-8,因为当我使用 ISO-8859-1 解码并使用 UTF-8 编码时,它已经在 UTF-8 中,值会发生变化,即) á改成这个Ã

有什么方法可以将所有类型的编码转换为 UTF-8 吗?

【问题讨论】:

    标签: python python-requests content-encoding


    【解决方案1】:

    当您有一个text/* 响应并且没有在响应标头中指定内容类型时,Requests 会将response.encoding 属性设置为ISO-8859-1

    Encoding section of the Advanced documentation

    Requests 唯一不会这样做的情况是,如果 HTTP 标头中没有明确的字符集并且Content-Type 标头包含text在这种情况下,RFC 2616 指定默认字符集必须为 ISO-8859-1。在这种情况下,请求遵循规范。如果您需要不同的编码,您可以手动设置Response.encoding 属性,或使用原始Response.content

    我的大胆强调。

    您可以通过在 Content-Type 标头中查找 charset 参数来对此进行测试:

    resp = requests.get(....)
    encoding = resp.encoding if 'charset' in resp.headers.get('content-type', '').lower() else None
    

    您的 HTML 文档在 <meta> 标头中指定了内容类型,并且该标头具有权威性:

    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    

    HTML 5 还定义了一个&lt;meta charset="..." /&gt; 标签,参见<meta charset="utf-8"> vs <meta http-equiv="Content-Type">

    如果 HTML 页面包含具有不同编解码器的此类标头,则您应该将其重新编码为 UTF-8。在这种情况下,您至少必须更正该标题

    使用 BeautifulSoup:

    # pass in explicit encoding if set as a header
    encoding = resp.encoding if 'charset' in resp.headers.get('content-type', '').lower() else None
    content = resp.content
    soup = BeautifulSoup(content, from_encoding=encoding)
    if soup.original_encoding != 'utf-8':
        meta = soup.select_one('meta[charset], meta[http-equiv="Content-Type"]')
        if meta:
            # replace the meta charset info before re-encoding
            if 'charset' in meta.attrs:
                meta['charset'] = 'utf-8'
            else:
                meta['content'] = 'text/html; charset=utf-8'
        # re-encode to UTF-8
        content = soup.prettify()  # encodes to UTF-8 by default
    

    同样,其他文档标准也可能指定特定的编码;例如,XML 始终是 UTF-8,除非由 &lt;?xml encoding="..." ... ?&gt; XML 声明指定,这也是文档的一部分。

    【讨论】:

    • 给定的 sn-ps 为 URL 产生 None 类型错误,例如 http://www.uraniumenergy.com/contact_us/contact_information ,您能说说为什么会发生这种情况以及如何避免它吗?。
    • @The6thSense:不知道;当我尝试它时,我没有收到任何错误。你有追溯吗?
    • 抱歉回复晚了。我已将回溯添加到问题中,当我执行dir(soup) 时,我没有得到select_one 我认为这是导致错误的原因。
    • @The6thSense:升级BeautifulSoup;该方法相当新(在 2015 年 7 月发布的 4.4.0 中添加)。
    • @The6thSense:或者,使用soup.select(...),如果返回的列表不为空,则使用第一个元素。
    【解决方案2】:

    请求将首先检查 HTTP 标头中的编码:

    print obj.headers['content-type']
    

    输出:

    text/html
    

    没有正确解析编码猜测的类型,因此它指定了默认的 ISO-8859-1。

    docs 中查看更多信息。

    【讨论】:

      【解决方案3】:

      请求replies on HTTP Content-Type 响应标头和chardet。对于text/html 的常见情况,它假定默认为ISO‌-8859-1。问题是 Requests 对 HTML 元标记一无所知,它可以指定不同的文本编码,例如&lt;meta charset="utf-8"&gt;&lt;meta http-equiv="content-type" content="text/html; charset=UTF‌-8"&gt;

      一个好的解决方案是使用 BeautifulSoup 的“Unicode, Dammit”功能,像这样:

      from bs4 import UnicodeDammit
      import requests
      
      
      url = 'http://www.reynamining.com/nuevositio/contacto.html'
      r = requests.get(url)
      
      dammit = UnicodeDammit(r.content)
      r.encoding = dammit.original_encoding
      
      print(r.text)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-02-08
        相关资源
        最近更新 更多