让JSON对象接受字节或让urlopen输出字符串

14 浏览
0 Comments

让JSON对象接受字节或让urlopen输出字符串

使用Python 3,我正在从URL请求一个json文档。\n

response = urllib.request.urlopen(request)

\nresponse对象是一个类似文件的对象,具有readreadline方法。通常,可以通过以文本模式打开的文件来创建JSON对象。\n

obj = json.load(fp)

\n我想做的是:\n

obj = json.load(response)

\n然而,这样做不起作用,因为urlopen以二进制模式返回文件对象。\n当然,有一种解决方法:\n

str_response = response.read().decode('utf-8')
obj = json.loads(str_response)

\n但这样做感觉不好...\n是否有更好的方法可以将字节文件对象转换为字符串文件对象?或者我是否遗漏了urlopenjson.load的某些参数来提供编码?

0
0 Comments

问题的原因:

在上述代码中,我们使用了urlopen函数从一个URL获取数据,并将其读取为字节流。然后,我们使用decode方法将字节流解码为字符串,并将其传递给json.loads函数来解析为JSON对象。然而,这种方法可能会导致一些问题。

解决方法:

一种解决方法是让json.loads函数接受字节流作为输入。这样,我们就不需要将字节流转换为字符串了。可以通过将response直接传递给json.loads函数来实现:

obj = json.loads(response)

另一种解决方法是让urlopen函数输出字符串而不是字节流。可以通过在urlopen函数调用中添加一个参数来指定返回的数据类型为字符串:

response = urlopen("site.com/api/foo/bar").read().decode('utf8')

这样,我们就可以直接将response传递给json.loads函数,而无需进行任何解码操作。

我们可以通过让JSON对象接受字节流或让urlopen函数输出字符串来解决这个问题。

0
0 Comments

问题的原因是urlopen函数输出的是bytes类型的数据,而JSON对象只接受字符串类型的数据。解决方法是让JSON对象接受bytes类型的数据,或者让urlopen函数输出字符串类型的数据。

HTTP发送的是字节数据。如果所请求的资源是文本类型,字符编码通常通过Content-Type HTTP头部或其他机制(如RFC、HTML meta标签)来指定。

urllib库应该知道如何将字节编码为字符串,但它过于天真——它是一个功能弱、非Pythonic的库。

《Dive Into Python 3》提供了对这种情况的概述。

你的“解决方法”是正确的,尽管它感觉不对,但这是正确的做法。

虽然这可能是“正确”的做法,但如果有一件事我可以撤销关于Python 3的,那就是这个字节/字符串的麻烦。你会认为内置的库函数至少应该知道如何处理其他内置的库函数。我们使用Python的部分原因是其简单直观的语法。这个改变打乱了所有这些。

可以查看“requests”库,它可以自动处理这种情况。

这并不是内置库函数需要“知道如何”处理其他函数的情况。JSON被定义为对象的UTF-8表示,所以它不能自动解码它不知道编码的字节。我同意urlopen应该能够自动解码字节,因为它知道编码。不管怎样,我已经将Python标准库的解决方法发布为答案——你可以使用codecs模块对字节进行流式解码。

我不同意这一点。虽然明确地处理字节和字符串之间的差异是一件让人头疼的事情,但让语言为你进行一些隐式转换是一件更令人痛苦的事情。隐式的字节<->字符串转换是许多错误的源头,Python3在指出这些陷阱方面非常有帮助。但我同意库在这方面还有改进的空间。

在我看来,失败的原因是首先将字符串强制为Unicode。

不,字符串必须是Unicode,如果你想要的软件能在英国或美国以外的其他地方使用。几十年来,我们一直在ASCII委员会的狭隘世界观下受苦。Python3终于做对了。这可能与Python起源于欧洲有关...

0
0 Comments

问题的出现原因是在Python 3.4.3中尝试使用json.load(reader(response))时出现了TypeError: the JSON object must be str, not 'StreamReader'的错误。解决方法是使用json.load()而不是json.loads()来加载JSON对象。

文章标题:让JSON对象接受bytes或让urlopen输出字符串的问题及解决方法

Python的标准库提供了很好的解决方案...

import codecs
reader = codecs.getreader("utf-8")
obj = json.load(reader(response))

这个方法适用于Python2和Python3。

文档:Python 2, Python3

我在Python 3.4.3中尝试这个答案时出现了错误,但不确定为什么。错误信息是TypeError: the JSON object must be str, not 'StreamReader'。

你可能是使用了json.loads()而不是json.load()吗?

如果能够使用响应中指定的编码而不是默认使用utf-8编码,那就更好了:response.headers.get_content_charset()。如果没有指定编码,则返回None,并且在Python2中不存在。

实际应用中可能需要小心一些;根据定义,JSON始终是UTF-8、UTF-16或UTF-32编码(实际上很可能是UTF-8),因此如果Web服务器返回了其他编码,那可能是Web服务器软件的配置错误而不是真正非标准的JSON。

JSON本身是一种文本格式,它对字符编码和字节一无所知。你可以使用任何字符编码将其存储在磁盘上。虽然application/json媒体类型的RFC规范说:“JSON文本应该使用UTF-8、UTF-16或UTF-32编码。”也就是说,Web服务器必须仅使用这些编码。此外,对application/json没有定义charset参数,并且最近的RFC规范中也没有检测编码的方法。这使得UTF-8成为唯一的选择。

在Python 2中,可以使用response.headers.getparam('charset')来获取编码,参考A good way to get the charset/encoding of an HTTP response in Python。尽管如我在前面的评论中所说:这对于JSON无帮助。

当我在Python 3.5中使用时,出现了"AttributeError: 'bytes' object has no attribute 'read'"的错误。

你可能是将一个bytes对象作为response变量传递而不是一个类似文件的对象吗?如果你已经有一个bytes对象并且只想解码它,你可以简单地调用它的decode(encoding)方法。

根据RFC8259,"注意:此注册表未定义"charset"参数。添加一个"charset"参数对符合规范的接收者实际上没有影响。"因此,是否更好地信任、忽略或信任但在经过启发式评估后绕过服务器选择发送的charset,可能是一个非常琐碎的问题。

参考我的上面的评论中的链接,其中明确说道:"未定义charset参数..."

0