使用正确的字符编码(python requests + beautifulsoup)

时间:2017-09-16 11:16:44

标签: python encoding utf-8 python-requests

我在解析此网站时遇到问题:http://fm4-archiv.at/files.php?cat=106

它包含特殊字符,如变音符号。见这里:enter image description here

我的Chrome浏览器会正确显示变音符号,如上面的屏幕截图所示。但是在其他页面上(例如:http://fm4-archiv.at/files.php?cat=105),变音符号显示不正确,如下面的屏幕截图所示: enter image description here

元HTML标记在页面上定义了以下字符集:

<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/>

我使用python请求包来获取HTML,然后使用Beautifulsoup来获取所需的数据。我的代码如下:

r = requests.get(URL)
soup = BeautifulSoup(r.content,"lxml")

如果我打印编码(print(r.encoding),结果为UTF-8。如果我通过调用ISO-8859-1手动将编码更改为cp1252r.encoding = ISO-8859-1,则在控制台上输出数据时没有任何更改。这也是我的主要问题。

r = requests.get(URL)
r.encoding = 'ISO-8859-1'
soup = BeautifulSoup(r.content,"lxml")

仍会导致我的python IDE控制台输出中显示以下字符串:

Der Wildlöwenpfleger

而应该是

Der Wildlöwenpfleger

如何更改代码以正确解析变音符号?

2 个答案:

答案 0 :(得分:1)

我刚刚找到了两个解决方案。你能证实吗?

Soup = BeautifulSoup(r.content.decode('utf-8','ignore'),"lxml")

Soup = BeautifulSoup(r.content,"lxml", fromEncoding='utf-8')

两者都会产生以下示例输出:

Der Wildlöwenpfleger

修改 我只是想知道为什么这些工作,因为r.encoding无论如何都会产生UTF-8。这告诉我,请求无论如何都将数据作为UTF-8数据处理。因此,我想知道为什么.decode('utf-8','ignore')fromEncoding='utf-8'会产生所需的输出?

编辑2: 好吧,我想我现在明白了。 .decode('utf-8','ignore')fromEncoding='utf-8'表示实际数据编码为UTF-8,而Beautifulsoup应解析它,将其作为UTF-8编码数据处理,实际情况就是如此。

我认为requests已正确处理UTF-8,但BeautifulSoup没有。因此,我必须进行额外的解码。

答案 1 :(得分:1)

通常,使用r.content而不是使用r.text,这是使用由requests确定的编码的解码内容。

在这种情况下,requests将使用UTF-8解码传入的字节字符串,因为这是服务器在Content-Type标题中报告的编码:

import requests

r = requests.get('http://fm4-archiv.at/files.php?cat=106')

>>> type(r.content)    # raw content
<class 'bytes'>
>>> type(r.text)       # decoded to unicode
<class 'str'>    
>>> r.headers['Content-Type']
'text/html; charset=UTF-8'
>>> r.encoding
'UTF-8'

>>> soup = BeautifulSoup(r.text, 'lxml')

这将修复“Wildlöwenpfleger”问题,但是,页面的其他部分会开始中断,例如:

>>> soup = BeautifulSoup(r.text, 'lxml')     # using decoded string... should work
>>> soup.find_all('a')[39]
<a href="details.php?file=1882">Der Wildlöwenpfleger</a>
>>> soup.find_all('a')[10]
<a href="files.php?cat=87" title="Stermann und Grissemann sind auf Sommerfrische und haben Hermes ihren Salon �bergeben. Auf Streifz�gen durch die Popliteratur st��t Hermes auf deren gro�e Themen und h�rt mit euch quer. In der heutige">Salon Hermes (6 files)

显示“Wildlöwenpfleger”已修复,但现在“übergeben”和第二个链接中的其他链接已损坏。

在一个HTML文档中似乎使用了多种编码。第一个链接使用UTF-8编码:

>>> r.content[8013:8070].decode('iso-8859-1')
'<a href="details.php?file=1882">Der Wildlöwenpfleger</a>'

>>> r.content[8013:8070].decode('utf8')
'<a href="details.php?file=1882">Der Wildlöwenpfleger</a>'

但第二个链接使用ISO-8859-1编码:

>>> r.content[2868:3132].decode('iso-8859-1')
'<a href="files.php?cat=87" title="Stermann und Grissemann sind auf Sommerfrische und haben Hermes ihren Salon übergeben. Auf Streifzügen durch die Popliteratur stößt Hermes auf deren große Themen und hört mit euch quer. In der heutige">Salon Hermes (6 files)\r\n</a>'

>>> r.content[2868:3132].decode('utf8', 'replace')
'<a href="files.php?cat=87" title="Stermann und Grissemann sind auf Sommerfrische und haben Hermes ihren Salon �bergeben. Auf Streifz�gen durch die Popliteratur st��t Hermes auf deren gro�e Themen und h�rt mit euch quer. In der heutige">Salon Hermes (6 files)\r\n</a>'

显然,在同一个HTML文档中使用多个编码是不正确的。除了联系文档的作者并要求更正之外,您可以轻松地处理混合编码。也许你可以在处理时对数据运行chardet.detect(),但这不会令人愉快。