【问题标题】:Python 2 vs. Python 3 - urllib formatsPython 2 与 Python 3 - urllib 格式
【发布时间】:2011-03-08 22:41:58
【问题描述】:

我已经厌倦了试图弄清楚为什么这段代码在 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 的回答通过将 IO 设置为 utf8 为脚本在 Python 3 中工作提供了一种方法。但是仍然存在一个问题:为什么代码在 Python 2 中有效,而在 Python 3 中无效?

【问题讨论】:

    标签: python json python-3.x compatibility urllib


    【解决方案1】:

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

    在 Py3 中,ur = response.decode('utf8') 非常适合我,下面的 json.loads(ur) 也是如此。也许错误的复制和粘贴影响了您的 2 到 3 转换尝试。

    【讨论】:

    • 哎呀,我会修复代码错误...我尝试重新格式化以进行显示,但在此过程中搞砸了。 :P 不管怎样,解析后我无法查看数据(使用简单的“打印(数据)”),因为它给了我charmap错误。
    • @Daniel,你得到数据之后的问题似乎是与这个关于获取数据的问题不同的问题(我的回答似乎是回应- 尽管您似乎不同意,因为您甚至没有投票!)。如果data 是指json.loads(response),我可以print 它没有任何问题(在我的Mac Terminal.app 上,它支持UTF-8)。你的 sys.stdout.encoding 是什么?在启动 Python 3 之前,您是否正确设置了环境变量 PYTHONIOENCODING: Encoding[:errors] used for stdin/stdout/stderr?等等——完全不同的问题,见。
    • 对不起,如果我一开始不清楚。核心问题是我无法使用解析后的数据,无论出于何种原因(打印只是它的开始;如果我不能打印它,那么我在下面的某个地方读取数据时会遇到麻烦)。我会检查编码,我只想说它在我的 W7 机器上不起作用。
    • @Daniel,如果你不能打印它,那么这个问题很可能与你的 Windows 终端的输出能力无关除了——如en.wikipedia.org/wiki/Code_page 说,“最知名的代码页 [...] 将所有代码点都放入 8 位中,并且除了将每个代码点映射到单个位图之外不涉及任何其他内容”,这意味着他们不能显示大多数 Unicode 字符。这不会阻止您以任何其他方式使用您的数据 - 我们可以在问答中更好地讨论 Windows 上的 Unicode 问题好多,而不是在 cmets 中拥挤!
    • 如果只是Windows终端的输出能力,那为什么代码在Python 2中可以工作?
    【解决方案2】:

    取决于你的 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)
    

    【讨论】:

    • 您可能需要提供解释以澄清您的代码。
    【解决方案3】:

    请在另一个 Unicode 相关问题中查看 that 答案。

    现在:Python 3 str(它是 Python 2 unicode)类型是一个理想化的对象,因为它处理的是“字符”,而不是“字节”。为了用于磁盘/网络数据/从磁盘/网络数据中使用这些字符,需要通过“转换表”(即编码又名代码页)将字节编码为字节/解码字节。由于操作系统的多样性,Python 历来避免猜测该编码应该是什么。多年来,这种情况一直在改变,但仍然是“面对歧义,拒绝猜测的诱惑”的原则。适用。

    谢天谢地,Web 服务器让您的工作更轻松。您上面的response 应该会为您提供所需的所有额外信息:

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

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

    【讨论】:

      【解决方案4】:

      这是一种在两个版本之间都兼容的方法 - 它首先将字节数据转换为字符串,然后加载字符串。

      import json
      try:
          from urllib.request import Request, urlopen #python3+
      except ImportError:
          from urllib2 import Request, urlopen        #python2
      
      url = 'https://jsonfeed.org/feed.json'
      request = Request(url)
      response_json_string = urlopen(request).read().decode('utf8')
      response_json_object = json.loads(response_json_string)
      

      【讨论】:

        猜你喜欢
        • 2019-07-21
        • 2016-02-14
        • 2012-09-25
        • 2011-08-16
        • 2016-02-04
        • 1970-01-01
        • 2015-10-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多