网站的Python正确编码(Beautiful Soup)

新手上路,请多包涵

我正在尝试加载一个 html 页面并输出文本,即使我正确获取网页,BeautifulSoup 以某种方式破坏了编码。

来源:

 # -*- coding: utf-8 -*-
import requests
from BeautifulSoup import BeautifulSoup

url = "http://www.columbia.edu/~fdc/utf8/"
r = requests.get(url)

encodedText = r.text.encode("utf-8")
soup = BeautifulSoup(encodedText)
text =  str(soup.findAll(text=True))
print text.decode("utf-8")

摘录输出:

 ...Odenw\xc3\xa4lderisch...

这应该是 Odenwälderisch

原文由 user1767754 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 431
2 个回答

你犯了两个错误;您错误地处理了编码,并且将结果列表视为可以安全地转换为字符串而不会丢失信息的东西。

首先,不要使用 response.text !这不是 BeautifulSoup 的错,您正在重新编码 Mojibake 。当服务器未明确指定编码时, requests 库将默认为 text/* 内容类型的 Latin-1 编码,因为 HTTP 标准规定这是默认值。

请参阅 高级 文档的 编码 部分

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

大胆强调我的。

改为 response.content 原始数据:

 soup = BeautifulSoup(r.content)

我看到您正在使用 BeautifulSoup 3。您真的想升级到 BeautifulSoup 4;版本 3 已于 2012 年停产,并且包含多个错误。安装 beautifulsoup4 项目,并使用 from bs4 import BeautifulSoup

BeautifulSoup 4 通常可以很好地确定解析时使用的正确编码,无论是从 HTML <meta> 标记还是对提供的字节进行统计分析。如果服务器确实提供了一个字符集,您仍然可以将其从响应中传递到 BeautifulSoup,但请先测试 requests 是否使用了默认值:

 encoding = r.encoding if 'charset' in r.headers.get('content-type', '').lower() else None
parser = 'html.parser'  # or lxml or html5lib
soup = BeautifulSoup(r.content, parser, from_encoding=encoding)

最后但同样重要的是,使用 BeautifulSoup 4,您可以使用 soup.get_text() 从页面中提取所有文本:

 text = soup.get_text()
print text

您而是将 _结果列表_( soup.findAll() 的返回值)转换为字符串。这永远行不通,因为 Python 中的容器在列表中的每个元素上使用 repr() 来生成 _调试字符串_,对于字符串,这意味着您将获得任何非可打印 ASCII 字符的转义序列。

原文由 Martijn Pieters 发布,翻译遵循 CC BY-SA 4.0 许可协议

这不是 BeautifulSoup 的错。在使用 BeautifulSoup 之前,您可以通过打印出 encodedText 来看到这一点:非 ASCII 字符已经是乱码了。

这里的问题是您混淆了字节和字符。要全面了解差异,请阅读 Joel 的一篇文章,但要点是字节是字节(8 位组,没有任何附加含义),而字符是组成文本字符串的东西。 编码将字符转换为字节,解码将字节转换回字符。

查看 requests 文档 显示 r.text字符 组成,而不是字节。你不应该编码它。如果您尝试这样做,您将创建一个字节字符串,当您尝试将其视为字符时,就会发生不好的事情。

有两种方法可以解决这个问题:

  1. 按照 Martijn 的建议,使用存储在 r.content 中的原始未解码字节。然后你可以自己解码它们,把它们变成字符。
  2. requests 进行解码,但要确保它使用正确的编解码器。由于您知道在这种情况下是 UTF-8,因此您可以设置 r.encoding = 'utf-8' 。如果您在访问 r.text 之前 执行此操作,那么当您访问 r.text 时,它将被正确解码,并且您将获得一个字符串。您根本不需要弄乱字符编码。

顺便说一下,Python 3 使维护字符串和字节串之间的区别变得更容易一些,因为它要求您使用不同类型的对象来表示它们。

原文由 David Z 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题