Beautiful Soup - 编码

所有 HTML 或 XML 文档都是以某种特定编码编写的,例如 ASCII 或 UTF-8。 但是,当您将该 HTML/XML 文档加载到 BeautifulSoup 时,它已被转换为 Unicode。

>>> markup = "<p>I will display £</p>"
>>> Bsoup = BeautifulSoup(markup)
>>> Bsoup.p
<p>I will display £</p>
>>> Bsoup.p.string
'I will display £'

以上行为是因为 BeautifulSoup 内部使用名为 Unicode 的子库 Dammit 来检测文档的编码,然后将其转换为 Unicode。

然而,并非所有时候,Unicode,Dammit 都能正确识别。 由于逐字节搜索识别文档以编码,因此需要花费大量时间。 如果您已经知道编码并将其作为 from_encoding 传递给 BeautifulSoup 构造函数,则可以节省一些时间并避免错误。

下面是 BeautifulSoup 将 ISO-8859-8 文档错误识别为 ISO-8859-7 的示例 −

>>> markup = b"<h1>\xed\xe5\xec\xf9</h1>"
>>> soup = BeautifulSoup(markup)
>>> soup.h1
<h1>νεμω</h1>
>>> soup.original_encoding
'ISO-8859-7'
>>>

要解决上述问题,请使用 from_encoding 将其传递给 BeautifulSoup −

>>> soup = BeautifulSoup(markup, from_encoding="iso-8859-8")
>>> soup.h1
<h1>ולש </h1>
>>> soup.original_encoding
'iso-8859-8'
>>>

BeautifulSoup 4.4.0 添加的另一个新功能是 exclude_encoding。 当您不知道正确的编码,Dammit 显示错误结果时,可以使用它。

>>> soup = BeautifulSoup(markup, exclude_encodings=["ISO-8859-7"])

输出编码

BeautifulSoup 的输出是 UTF-8 文档,与 BeautifulSoup 中输入的文档无关。 在文档下方,波兰语字符以 ISO-8859-2 格式显示。

html_markup = """
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV="content-type" CONTENT="text/html; charset=iso-8859-2">
</HEAD>
<BODY>
ą ć ę ł ń ó ś ź ż Ą Ć Ę Ł Ń Ó Ś Ź Ż
</BODY>
</HTML>
"""

>>> soup = BeautifulSoup(html_markup)
>>> print(soup.prettify())
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
   <head>
      <meta content="text/html; charset=utf-8" http-equiv="content-type"/>
   </head>
   <body>
      ą ć ę ł ń ó ś ź ż Ą Ć Ę Ł Ń Ó Ś Ź Ż
   </body>
</html>

在上面的示例中,如果您注意到,<meta> 标签已被重写以反映从 BeautifulSoup 生成的文档现在是 UTF-8 格式。

如果您不想要 UTF-8 格式的输出,您可以在 prettify() 中分配所需的编码。

>>> print(soup.prettify("latin-1"))
b'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\n<html>\n <head>\n <meta content="text/html; charset=latin-1" http-equiv="content-type"/>\n </head>\n <body>\n ą ć ę ł ń \xf3 ś ź ż Ą Ć Ę Ł Ń \xd3 Ś Ź Ż\n </body>\n</html>\n'

在上面的例子中,我们已经对完整的文档进行了编码,但是您可以对 soup 中的任意特定元素进行编码,就好像它们是 python 字符串一样 −

>>> soup.p.encode("latin-1")
b'<p>0My first paragraph.</p>'
>>> soup.h1.encode("latin-1")
b'<h1>My First Heading</h1>'

任何不能用您选择的编码表示的字符都将被转换为数字 XML 实体引用。 下面是一个这样的例子 −

>>> markup = u"<b>\N{SNOWMAN}</b>"
>>> snowman_soup = BeautifulSoup(markup)
>>> tag = snowman_soup.b
>>> print(tag.encode("utf-8"))
b'<b>\xe2\x98\x83</b>'

如果您尝试将上述内容编码为"latin-1"或"ascii",它会生成 "☃" ,表示没有表示法。

>>> print (tag.encode("latin-1"))
b'<b>☃</b>'
>>> print (tag.encode("ascii"))
b'<b>☃</b>'

Unicode, Dammit

Unicode, Dammit 主要用于传入文档的格式未知(主要是外语)并且我们想以某种已知格式(Unicode)进行编码, 并且我们不需要 Beautifulsoup 来完成这些工作。