BeautifulSoup 4将HTML实体转换为unicode,但在使用print时获取垃圾字符

时间:2013-12-17 02:29:56

标签: python unicode beautifulsoup html-entities

我正在尝试使用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")

2 个答案:

答案 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以避免垃圾进入控制台。