use*_*754 9 python encoding beautifulsoup utf-8 mojibake
我正在尝试加载一个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")
Run Code Online (Sandbox Code Playgroud)
摘录输出:
...Odenw\xc3\xa4lderisch...
Run Code Online (Sandbox Code Playgroud)
这应该是Odenwälderisch
Mar*_*ers 32
你犯了两个错误; 您是错误处理编码,并且您将结果列表视为可以安全地转换为字符串而不丢失信息的内容.
首先,不要使用response.text
!这里不是BeautifulSoup故障,你正在重新编码一个Mojibake.该requests
库将默认为Latin-1编码的text/*
内容类型时,服务器没有明确指定编码,因为HTTP标准的规定,这是默认.
唯一的一次请求不会做到这一点,如果没有明确的字符集是存在于HTTP头,并在
Content-Type
头中包含text
.在这种情况下,RFC 2616指定默认字符集必须是ISO-8859-1
.在这种情况下,请求遵循规范.如果需要不同的编码,可以手动设置Response.encoding
属性,或使用rawResponse.content
.
大胆强调我的.
传入response.content
原始数据:
soup = BeautifulSoup(r.content)
Run Code Online (Sandbox Code Playgroud)
我看到你正在使用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
soup = BeautifulSoup(r.content, from_encoding=encoding)
Run Code Online (Sandbox Code Playgroud)
最后但并非最不重要的是,使用BeautifulSoup 4,您可以使用soup.get_text()
以下方法从页面中提取所有文本:
text = soup.get_text()
print text
Run Code Online (Sandbox Code Playgroud)
而是将结果列表(返回值soup.findAll()
)转换为字符串.这永远不会起作用,因为Python中的容器使用repr()
列表中的每个元素来生成调试字符串,而对于字符串,这意味着您可以获得任何不是可打印ASCII字符的转义序列.
这不是BeautifulSoup的错。您可以encodedText
在使用BeautifulSoup之前通过打印出来查看此内容:非ASCII字符已经乱码。
这里的问题是您混淆了字节和字符。为了更好地了解它们之间的区别,请阅读Joel的文章之一,但要点是字节是字节(8位的组,没有附加任何其他含义),而字符是组成文本字符串的东西。编码将字符转换成字节,而解码将字节转换成字符。
查看requests
文档显示,它r.text
是由字符而不是字节组成的。您不应该对其进行编码。如果尝试这样做,则会创建一个字节字符串,并且当您尝试将其视为字符时,会发生不好的事情。
解决此问题的方法有两种:
r.content
,如马亭建议。然后,您可以自己解码它们以将其转换为字符。requests
进行解码,但是只要确保它使用正确的编解码器即可。由于您知道在这种情况下为UTF-8,因此可以设置r.encoding = 'utf-8'
。如果您在访问之前执行此操作r.text
,那么在访问时r.text
,它将被正确解码,并且您会得到一个字符串。您根本不需要弄乱字符编码。顺便说一句,Python 3使维护字符串和字节字符串之间的差异变得更加容易,因为它要求您使用不同类型的对象来表示它们。