我正在尝试使用BeautifulSoup 4从网上抓取文本来解析它。将bs4处理过的文本打印到控制台时,我遇到了一个问题。每当我点击一个最初是HTML实体的角色时,就像’我在控制台上得到了垃圾字符。我相信bs4正在将这些实体正确转换为unicode,因为如果我尝试使用其他编码来打印文本,它会抱怨字符的适当缺乏unicode映射(比如u'\ u2019。)我不知道为什么打印功能对这些字符感到困惑。我已经尝试更改字体,这会改变垃圾字符,并且我在使用美国英语语言环境的Windows 7机器上。这是我的代码供参考,任何帮助表示赞赏。提前谢谢!
#!/usr/bin/python
import json
import urllib2
import cookielib
import bs4
cj = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
url = "http://api.nytimes.com/svc/search/v2/articlesearch.json?q=Tiguan\
&page=0&api-key=blah"
response = opener.open(url)
articles = response.read()
decoded = json.loads(articles)
totalpages = decoded['response']['meta']['hits']/10
for page in range(totalpages + 1):
if page>0:
url = "http://api.nytimes.com/svc/search/v2/articlesearch.json?\
q=Tiguan&page=" + str(page) + "&api-key=blah"
response = opener.open(url)
articles = response.read()
decoded = json.loads(articles)
for url in decoded['response']['docs']:
print url['web_url']
urlstring = url['web_url']
art = opener.open(urlstring)
soup = bs4.BeautifulSoup(art.read())
goodstuff = soup.findAll('nyt_text')
for tag in goodstuff:
print tag.prettify().encode("UTF")
答案 0 :(得分:7)
问题与bs4,HTML实体或其他任何内容无关。在大多数Windows系统上,您可以使用单行程序重现完全相同的行为,以打印出当您尝试打印时显示为垃圾的相同字符,如下所示:
print u'\u2019'.encode('UTF-8')
问题在于,与绝大多数Windows系统一样(2013年没有其他任何人使用过),您的默认字符集不是UTF-8,而是类似于CP1252。
因此,当您将Unicode字符串编码为UTF-8并将这些字节打印到控制台时,控制台会将它们解释为CP1252。在这种情况下,这意味着您获得’
而不是’
。
更改字体无济于事。 \u2013
的UTF-8编码是三个字节\xe2
,\x80
和\x99
,这三个字节的CP1252含义为â
,{ {1}}和€
。
如果要手动编码控制台,则需要编码为右字符集,即控制台实际使用的字符集。您可以将其设为™
。
当然,尝试为正确的字符集编码事物可能会遇到异常,因为像CP1252这样的8位字符集只能处理Unicode中110K字符中的大约240个字符。处理这种情况的唯一方法是使用sys.stdout.encoding
errors
参数来忽略它们或用替换字符替换它们。
同时,如果你还没有阅读Unicode HOWTO,你真的需要。特别是如果你打算坚持使用Python 2.x和Windows。
如果您想知道为什么一些命令行程序似乎能够解决这些问题:Microsoft对字符集问题的解决方案是创建一组使用16位字符而不是8位的并行API -bit,这些API总是使用UTF-16。不幸的是,很多东西,比如微软为控制台提供的便携式stdio包装器以及Python 2.x所依赖的,只有8位API。这意味着问题根本没有解决。 Python 3.x不再使用这些包装器,并且一直在讨论如何将未来版本的UTF-16与控制台进行对话。但即使这种情况发生在3.4(这似乎不太可能),只要您使用2.x,这对您无济于事。
答案 1 :(得分:3)
@abarnert's answer包含对此问题的良好解释。
在您的特定情况下,您只需将encoding
参数传递给prettify()
,而不是默认utf-8
。
如果要打印到控制台,可以尝试直接打印Unicode:
print soup.prettify(encoding=None, formatter='html') # print Unicode
It may fail。如果你通过ascii
;那么BeautifulSoup
可以使用数字字符引用而不是非ascii字符:
print soup.prettify('ascii', formatter='html')
它假设当前的Windows代码页是基于ascii的编码(大多数都是这样)。如果通过管道将输出重定向到文件或其他程序,它也应该有效。
为了便于携带,您可以始终打印Unicode(上面encoding=None
)并使用PYTHONIOENCODING
来获取适当的字符编码,例如,utf-8用于文件,管道和ascii:xmlcharrefreplace
以避免垃圾进入控制台。