【问题标题】:Latin encoding issue拉丁编码问题
【发布时间】:2017-09-24 00:06:23
【问题描述】:

我正在开发一个 python 网络爬虫来从this webpage 中提取数据。它包含拉丁字符,如ą、č、ę、ė、į、š、ų、ū、ž。我使用 BeautifulSoup 来识别编码:

def decode_html(html_string):
    converted = UnicodeDammit(html_string)
    print(converted.original_encoding)
    if not converted.unicode_markup:
        raise UnicodeDecodeError(
            "Failed to detect encoding, tried [%s]",
            ', '.join(converted.tried_encodings))
    return converted.unicode_markup

它似乎总是使用的编码是“windows-1252”。但是,当打印到文件或控制台时,这会将 ė 等字符转换为 ë 并将 ų 转换为 ø。我使用 lxml 库来抓取数据。所以我会认为它使用了错误的编码,但奇怪的是,如果我使用lxml.html.open_in_browser(decoded_html),所有字符都恢复正常。如何在没有所有 mojibake 的情况下将字符打印到文件中?

这是我用于输出的内容:

def write(filename, obj):
with open(filename, "w", encoding="utf-8") as output:
    json.dump(obj, output, cls=CustomEncoder, ensure_ascii=False)
return

【问题讨论】:

    标签: python encoding web-scraping beautifulsoup lxml


    【解决方案1】:

    来自您尝试加载的特定网页上设置的 HTTP 标头:

    Content-Type:text/html; charset=windows-1257
    

    因此 Windows-1252 将导致无效结果。 BeautifulSoup 做了一个猜测(基于统计模型),并且猜错了。正如您所注意到的,使用 1252 会导致代码点不正确:

    >>> 'ė'.encode('cp1257').decode('cp1252')
    'ë'
    >>> 'ų'.encode('cp1257').decode('cp1252')
    'ø'
    

    CP1252 是 BeautifulSoup 中基本字符集检测实现的后备。您可以通过安装外部库来提高 BeautifulSoup 字符检测代码的成功率;支持chardetcchardet。这两个库分别猜测 MacCyrillic 和 ISO-8859-13(都错了,但 cchardet 非常接近,也许已经足够接近了)。

    在这种特定情况下,您可以改用 HTTP 标头。在请求中,我一般使用:

    import requests
    from bs4 import BeautifulSoup
    from bs4.dammit import EncodingDetector
    
    resp = requests.get(url)
    http_encoding = resp.encoding if 'charset' in resp.headers.get('content-type', '').lower() else None
    html_encoding = EncodingDetector.find_declared_encoding(resp.content, is_html=True)
    encoding = html_encoding or http_encoding
    soup = BeautifulSoup(resp.content, 'lxml', from_encoding=encoding)
    

    如果服务器明确设置,以上仅使用响应中的编码,并且没有 HTML <meta> 标头。对于text/* mime-types,HTTP 指定应将响应视为使用 Latin-1,requests 也遵循该响应,但该默认值对于大多数 HTML 数据是不正确的。

    【讨论】:

    • 这不是有一个不同的潜在问题,它总是会用字符集标头中提供的编码覆盖文档内指定的编码吗?
    • @pvg: 是的,如果服务器明确设置了编码并且 HTML 文档设置了一个(例如通过元标头),那么在这种情况下服务器内容-类型获胜。我将使用首先查找 HTML 声明的解决方案进行更新。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-09-18
    • 1970-01-01
    • 2011-05-28
    • 2016-02-17
    • 2011-01-27
    • 2013-08-28
    • 1970-01-01
    相关资源
    最近更新 更多