我正致力于改进Python IRC bot的字符编码支持,该机器人检索通道中提到其URL的页面的标题。
我正在使用的当前流程如下:
r = requests.get(url, headers={ 'User-Agent': '...' })
soup = bs4.BeautifulSoup(r.text, from_encoding=r.encoding)
title = soup.title.string.replace('\n', ' ').replace(...)
等。指定from_encoding=r.encoding
是一个好的开始,因为它允许我们在解析页面时从charset
标题中注意Content-Type
。
如果面临这种情况,则会在其<meta http-equiv … charset=…">
标题中指定<meta charset="…">
或charset
代替({1}}的页面。
我目前看到的方法如下:
Content-Type
标记,尝试注意我们在那里找到的任何编码,然后再回到请求'<meta>
,可能与之前的选项结合使用。我觉得这个选项很理想,但如果它已经存在,我宁愿不写这个代码。TL; DR有正确的方法吗?使用与浏览器使用类似的技术,使美丽的汤正确地注意到网页上任意HTML页面的字符编码?
答案 0 :(得分:2)
您似乎更希望在文档中声明的编码优先于HTTP标头中声明的编码。 UnicodeDammit(由BeautifulSoup在内部使用)如果您只是从头部传递编码,则反过来执行此操作。您可以通过从文档中读取已声明的编码并将其传递给第一个来解决此问题。大致(未经测试!):
r = requests.get(url, headers={ 'User-Agent': '...' })
is_html = content_type_header.split(';', 1)[0].lower().startswith('text/html')
declared_encoding = UnicodeDammit.find_declared_encoding(r.text, is_html=is_html)
encodings_to_try = [r.encoding]
if declared_encoding is not None:
encodings_to_try.insert(0, declared_encoding)
soup = bs4.BeautifulSoup(r.text, from_encoding=encodings_to_try)
title = soup.title...
答案 1 :(得分:1)
与更通用的模块ftfy不同,Unicode,Dammit采用的方法正是我正在寻找的(参见bs4/dammit.py
)。它会检查任何<meta>
标记提供的信息,而不是对问题进行更多盲目的猜测。
但是,当使用r.text
时,请求会尝试通过自动解码charset
标题中Content-Type
的网页来提供帮助,然后回退到ISO 8859-1不存在的页面,但Unicode,Dammit不会触及已经在unicode
字符串中的任何标记!
我选择的解决方案是使用r.content
代替:
r = requests.get(url, headers={ 'User-Agent': '...' })
soup = bs4.BeautifulSoup(r.content)
title = soup.title.string.replace('\n', ' ').replace(...)
等。我能看到的唯一缺点是,charset
只有Content-Type
的网页会受到Unicode,Dammit的猜测,因为BeautifulSoup
from_encoding=r.encoding
参数将覆盖Unicode,完全是Dammit。