关于json:Python 2与Python 3 – urllib格式

Python 2 vs. Python 3 - urllib formats

我真的厌倦了试图弄明白为什么这段代码在Python2中有效,而不是在Python3中。我只是想抓取一页JSON然后解析它。下面是python 2中的代码:

1
2
3
4
import urllib, json
response = urllib.urlopen("http://reddit.com/.json")
content = response.read()
data = json.loads(content)

我认为python 3中的等效代码是:

1
2
3
4
import urllib.request, json
response = urllib.request.urlopen("http://reddit.com/.json")
content = response.read()
data = json.loads(content)

但它在我脸上爆炸了,因为read()返回的数据是"字节"类型。然而,在我的生命中,我不能让它转换成JSON能够解析的东西。我从标题中知道reddit正试图将utf-8发回给我,但我似乎无法将字节解码为utf-8:

1
2
3
4
import urllib.request, json
response = urllib.request.urlopen("http://reddit.com/.json")
content = response.read()
data = json.loads(content.decode("utf8"))

我做错什么了?

编辑:问题是我无法使数据进入可用状态;即使JSON加载了数据,但其中的一部分是不可显示的,我希望能够将数据打印到屏幕上。

第二次编辑:看起来,问题更多地与打印有关,而不是与解析有关。亚历克斯的回答为脚本在python 3中工作提供了一种方法,将IO设置为utf8。但问题仍然存在:为什么代码在python 2中工作,而不是python 3?


您发布的代码可能是由于错误的剪切和粘贴操作造成的,因为在两个版本中它都是明显错误的(f.read()失败,因为没有定义fbarename)。

在Py3中,ur = response.decode('utf8')对我来说非常有效,下面的json.loads(ur)也是如此。可能是错误的复制和粘贴影响了2到3次转换尝试。


取决于您的Python版本,您必须选择正确的库。

对于Python 3.5

1
2
import urllib.request
data = urllib.request.urlopen(url).read().decode('utf8')

对于Python 2.7

1
2
3
import urllib
url = serviceurl + urllib.urlencode({'sensor':'false', 'address': address})  
uh = urllib.urlopen(url)


请在另一个与Unicode相关的问题中看到这个答案。

现在:python 3 str类型(即python 2 unicode类型)是一个理想化的对象,从这个意义上说,它处理的是"字符",而不是"字节"。为了用于/来自磁盘/网络数据,这些字符需要通过"转换表"(A.K.A编码A.K.A代码页)编码到字节中或从字节中解码。由于操作系统的多样性,python在历史上避免了猜测编码应该是什么;这一点多年来一直在改变,但仍然坚持"面对歧义,拒绝猜测的诱惑"的原则。

谢天谢地,Web服务器使您的工作更容易。您的上述response应向您提供所需的所有额外信息:

1
2
>>> response.headers['content-type']
'application/json; charset=UTF-8'

因此,每次向Web服务器发出请求时,都要检查Content-Type头中的字符集值,并使用该字符集将请求的数据解码为Unicode(python 3:bytes.decode(charset)str)。