你犯了两个错误;您错误地处理了编码,并且您将结果列表视为可以安全地转换为字符串而不会丢失信息的东西。
首先,不要使用response.text
!这不是 BeautifulSoup 的错,您正在重新编码Mojibake。当服务器没有明确指定编码时,该requests
库将默认为内容类型的 Latin-1 编码,因为 HTTP 标准规定这是默认值。text/*
请参阅高级文档的编码部分:
Requests 唯一不会这样做的情况是,如果 HTTP 标头中不存在显式字符集并且标Content-Type
头包含text
. 在这种情况下,RFC 2616 指定默认字符集必须是ISO-8859-1
. 在这种情况下,请求遵循规范。如果你需要不同的编码,你可以手动设置Response.encoding
属性,或者使用 raw Response.content
。
大胆强调我的。
而是传入response.content
原始数据:
soup = BeautifulSoup(r.content)
我看到您正在使用 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
parser = 'html.parser' # or lxml or html5lib
soup = BeautifulSoup(r.content, parser, from_encoding=encoding)
最后但同样重要的是,使用 BeautifulSoup 4,您可以使用以下方法从页面中提取所有文本soup.get_text()
:
text = soup.get_text()
print text
相反,您将结果列表(的返回值soup.findAll()
)转换为字符串。这永远不会起作用,因为 Python 中的容器使用repr()
列表中的每个元素来生成调试字符串,而对于字符串,这意味着您可以获得任何非可打印 ASCII 字符的转义序列。