Python 2与Python 3 - urllib格式
我真的很烦恼,为什么这段代码在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 个回答
请查看这个在另一个与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
)。
这要看你使用的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)
你发的代码看起来是因为剪切和粘贴出错了,因为这两个版本的代码明显都是错的(f.read()
会出错,因为没有定义f
这个变量)。
在Python 3中,ur = response.decode('utf8')
对我来说运行得很好,接下来用json.loads(ur)
也没问题。也许你在把代码从Python 2转换到Python 3的时候,剪切和粘贴出错了。