使用Beautiful Soup时,无需任何猜测即可正确检测编码

Del*_*ani 5 python beautifulsoup character-encoding

我正在努力改进Python IRC bot的字符编码支持,以检索在频道中提到其URL的页面的标题.

我正在使用的当前流程如下:

  1. 请求:

    r = requests.get(url, headers={ 'User-Agent': '...' })
    
    Run Code Online (Sandbox Code Playgroud)
  2. 美丽的汤:

    soup = bs4.BeautifulSoup(r.text, from_encoding=r.encoding)
    
    Run Code Online (Sandbox Code Playgroud)
  3. title = soup.title.string.replace('\n', ' ').replace(...) 等等

指定from_encoding=r.encoding是一个好的开始,因为它允许我们在解析页面时charsetContent-Type头部注意.

如果它的表面落在其标题上的页面指​​定a <meta http-equiv … charset=…"><meta charset="…">代替(或在顶部).charsetContent-Type

我目前看到的方法如下:

  1. 在解析页面时无条件地使用Unicode,Dammit.这是默认设置,但它似乎对我测试过的任何页面都无效.
  2. 在解析页面之前或之后无条件地使用ftfy.我不喜欢这个选项,因为它基本上依赖于我们(通常)拥有完美信息的任务的猜测.
  3. 编写代码来寻找合适的<meta>标签,尝试注意我们在那里找到的任何编码,然后再回到Requests' .encoding,可能与之前的选项结合使用.我觉得这个选项很理想,但如果它已经存在,我宁愿不写这个代码.

TL; DR是否有正确的方法来使美丽的汤正确地注意到网页上任意HTML页面的字符编码,使用与浏览器使用类似的技术?

tal*_*nat 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...
Run Code Online (Sandbox Code Playgroud)