Python 2与Python 3 - urllib格式

22 投票
4 回答
16609 浏览
提问于 2025-04-16 00:30

我真的很烦恼,为什么这段代码在Python 2中能正常工作,而在Python 3中却不行。我只是想抓取一页json数据,然后解析它。以下是Python 2中的代码:

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

以为 在Python 3中等价的代码应该是这样的:

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:

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

我哪里做错了?

补充说明:问题在于我无法把数据变成可用的状态;即使json能加载数据,但其中一部分无法显示,我想把数据打印到屏幕上。

第二次补充:问题似乎更多是和打印有关,而不是解析。Alex的回答提供了一种让脚本在Python 3中工作的方式,通过将输入输出设置为utf8。但我仍然有一个疑问:为什么这段代码在Python 2中可以工作,而在Python 3中却不行呢?

4 个回答

0

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

现在,Python 3中的str(相当于Python 2中的unicode)是一种理想化的对象,它处理的是“字符”,而不是“字节”。这些字符为了能够在磁盘或网络数据中使用,需要通过一个“转换表”进行编码成字节,或者从字节解码成字符,这个转换表也叫做编码或代码页。由于操作系统的多样性,Python历史上避免去猜测应该使用什么编码;虽然这几年有所变化,但“在面对模糊时,拒绝猜测的诱惑”这个原则依然适用。

幸运的是,网络服务器让你的工作变得简单。你上面的response应该提供了所有需要的额外信息:

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

所以,每次你向网络服务器发送请求时,都要检查Content-Type头部中的字符集值,并使用这个字符集将请求的数据解码成Unicode(在Python 3中是bytes.decode(charset)str)。

7

这要看你使用的Python版本,选择合适的库。

如果你用的是Python 3.5:

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

如果你用的是Python 2.7:

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

你发的代码看起来是因为剪切和粘贴出错了,因为这两个版本的代码明显都是错的(f.read()会出错,因为没有定义f这个变量)。

在Python 3中,ur = response.decode('utf8')对我来说运行得很好,接下来用json.loads(ur)也没问题。也许你在把代码从Python 2转换到Python 3的时候,剪切和粘贴出错了。

撰写回答