如何从python中的socket读取JSON?(JSON的增量解析)

cub*_*ube 10 python sockets json

我打开了一个套接字,我想从中读取一些json数据.问题是json标准库中的模块只能从字符串解析(load只读取整个文件并调用loads内部)它甚至看起来模块内部的所有方式都取决于参数是字符串.

这是套接字的一个真正问题,因为你永远无法将它全部读取为字符串,并且在实际解析之前你不知道要读取多少字节.

所以我的问题是:是否有(简单而优雅)的解决方法?是否有另一个可以递增地解析数据的json库?值得自己写吗?

编辑:这是XBMC jsonrpc api.没有消息信封,我无法控制格式.每条消息可以在一行或多行上.我可以编写一些简单的解析器,它只需要某种形式的getc函数并使用它来提供它s.recv(1),但这不是一个非常pythonic的解决方案,我有点懒,这样做:-)

Rus*_*ove 6

编辑:鉴于您没有定义协议,这没有用,但在其他上下文中可能有用。


假设它是一个流 (TCP) 套接字,您需要实现自己的消息帧机制(或使用现有的更高级别的协议来实现)。一种直接的方法是将每条消息定义为一个 32 位整数长度字段,后跟那么多字节的数据。

Sender:取JSON包的长度,用struct模块打包成4个字节,在socket上发送,然后发送JSON包。

Receiver:反复从socket中读取,直到至少有4个字节的数据,用于struct.unpack解包长度。从套接字读取,直到您至少有那么多数据,这就是您的 JSON 数据包;剩下的就是下一条消息的长度。

如果在某个时候您想通过同一个套接字发送由 JSON 以外的内容组成的消息,您可能需要在长度和数据负载之间发送消息类型代码;恭喜你,你又发明了另一个协议。

另一种稍微更标准的方法是 DJB 的Netstrings协议;它与上面提出的系统非常相似,但使用文本编码的长度而不是二进制;它由Twisted等框架直接支持。


Ada*_*eld 5

如果您要从 HTTP 流获取 JSON,请使用Content-Length标头来获取 JSON 数据的长度。例如:

import httplib
import json

h = httplib.HTTPConnection('graph.facebook.com')
h.request('GET', '/19292868552')
response = h.getresponse()
content_length = int(response.getheader('Content-Length','0'))

# Read data until we've read Content-Length bytes or the socket is closed
data = ''
while len(data) < content_length or content_length == 0:
    s = response.read(content_length - len(data))
    if not s:
        break
    data += s

# We now have the full data -- decode it
j = json.loads(data)
print j
Run Code Online (Sandbox Code Playgroud)


Pie*_*ton 3

你想要的是 ijson,一个增量 json 解析器。它可以在这里找到: https: //pypi.python.org/pypi/ijson/。用法应该很简单(从该页面复制):

import ijson.backends.python as ijson

for item in ijson.items(file_obj):
    # ...
Run Code Online (Sandbox Code Playgroud)

(对于那些喜欢独立的东西的人 - 从某种意义上说,它只依赖于标准库:我昨天写了一个关于 json 的小包装 - 但只是因为我不了解 ijson。它的效率可能要低得多。)

编辑:因为我发现事实上我的方法(的 cythonized 版本)比 ijson 更有效,所以我将其打包为一个独立的库 - 也请参阅这里的一些粗略基准:http ://pietrobattiston.it/jsaone