2013-12-17 25 views
3

我想从使用BeautifulSoup 4的Web刮取文本来解析它。将bs4处理后的文本输出到控制台时遇到问题。每当我碰到一个原本是HTML实体的角色,就像’我在控制台上得到垃圾字符。我相信bs4正在将这些实体正确地转换为unicode,因为如果我尝试使用另一种编码来打印文本,它会抱怨适当地缺少字符的unicode映射(如u'\ u2019)。我不确定为什么打印功能会对这些字符感到困惑。我试着改变字体,这会改变垃圾字符,并且在美国英语区域设置的Windows 7机器上。这里是我的代码供参考,任何帮助表示赞赏。提前致谢!BeautifulSoup 4将HTML实体转换为unicode,但使用打印时获取垃圾字符

#!/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

相关:[Python,Unicode和Windows控制台](http://stackoverflow.com/q/5419/4279) – jfs

+0

顺便说一句,你不是。 [奥巴马也得到了它](http://www.hanselman.com/blog/WhyTheAskObamaTweetWasGarbledOnScreenKnowYourUTF8UnicodeASCIIAndANSIDecodingMrPresident.aspx) – jfs

+0

@JFSebastian:我已经好几次几乎把一个问题标记为一个问题,但它充满了答案看起来不错,不是。我们确实需要收集所有不同笨重的解决方法,并解释每个问题,并明确指出,除非您停止使用Windows或Python 2.x,否则这些笨重的解决方法就像您将要获得的一样好... – abarnert

回答

6

该问题与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含义是â,

如果你想为控制台手动编码,你需要编码为右边的字符集,这是你的控制台实际使用的那个。您可以将其作为sys.stdout.encoding

当然,您可能会遇到异常,尝试对正确的字符集进行编码,因为像CP1252这样的8位字符集只能处理Unicode中110K字符的约240个字符。处理该问题的唯一方法是使用errors参数encode来忽略它们或将它们替换为替换字符。

同时,如果您还没有阅读Unicode HOWTO,您确实需要。尤其是如果你打算坚持使用Python 2.x和Windows。


如果你想知道为什么一些命令行程序似乎能够解决这些问题:微软的解决方案,以字符集问题是要创造出一个平行组API使用16位字符而不是8位,并且这些API始终使用UTF-16。不幸的是,许多事情,例如微软提供的用于与控制台交谈并且Python 2.x依赖的便携式stdio封装器,只有8位API。这意味着问题根本无法解决。 Python 3.x不再使用这些包装器,并且一直在讨论将未来版本的UTF-16作为控制台。但即使这种情况发生在3.4(这看起来不太可能),只要你使用2.x就不会帮助你。

+0

是的,谢谢你的回应。我尝试设置控制台的代码页,但那也没有效果。我选择的python版本是由我的学校提供​​的linux服务器的管理员决定的,我最终希望运行我的程序。我选择Windows是因为我使用工作提供的笔记本电脑来完成我的功课。我认为,只要将我的程序移动到服务器上,我应该可以,但是在开发过程中会让我感到很痛苦。也许我会看看替代控制台,看看有没有更好的unicode。再次感谢伟大的解释! – DaWisePug

+0

@DaWisePug:“我试着设置控制台的代码页”是什么意思?如果您实际上将Windows OEM代码页切换为UTF-8,或者将cmd.exe转换为使用UTF-8(其中任何一种可能会破坏其他所有类型),或者使用UTF-8友好的第三方控制台模拟器(有没有,建立一个X服务器和运行像rxvt?),你的代码应该工作。但我怀疑你没有做这些事情。 – abarnert

+0

我试图通过发出chcp 65001命令欺骗cmd.exe。这没有奏效。 – DaWisePug

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避免在控制台垃圾。

+0

这样做的结果是将HTML实体的纯文本打印到控制台,这可能会导致一个有用的解决方法。谢谢! – DaWisePug

+0

@DaWisePug:*名称*字符实体归因于'formatter ='html''。如果不合需要,请将其取出。 – jfs

+0

@DaWisePug:我已经更新了答案,提到了更通用的解决方案:打印Unicode,在特定情况下使用'PYTHONIOENCODING'。 – jfs

相关问题