如何解析tshark实时输出的JSON流?
解析tshark JSON输出流的最佳实践
你提到之前是逐行解析tshark的常规文本输出,现在切换到-T json的JSON数组格式(且只看到首个数据包),想要高效的流解析方案——毕竟如果是实时抓包或者处理大量数据包,把整个JSON数组加载到内存显然不现实。下面是几个实用的方案,按易用性排序:
方案1:让tshark输出换行分隔的JSON(最省心)
其实tshark从3.0版本开始支持-T ndjson格式,它会把每个数据包单独输出为一行JSON,完全避开了数组包裹的问题,直接就能逐行解析,和你之前处理常规输出的逻辑几乎一致!
使用命令:
tshark -i <接口> -T ndjson
然后在Python中处理的示例:
import subprocess import json # 启动tshark进程,获取输出流 proc = subprocess.Popen( ["tshark", "-i", "eth0", "-T", "ndjson"], stdout=subprocess.PIPE, text=True ) # 逐行解析每个数据包的JSON for line in proc.stdout: if line.strip(): # 跳过空行 packet = json.loads(line) # 处理数据包,比如打印源IP print(packet.get("ip.src", "N/A"))
这个方案不需要额外依赖,逻辑简单,适合大多数场景。如果你的tshark版本低于3.0,也可以用-l选项强制刷新输出,配合-T json加上-j指定要输出的字段(避免输出整个数组结构),不过ndjson是更标准的选择。
方案2:用流解析库处理JSON数组
如果必须使用-T json的数组格式,那么可以用支持增量解析的JSON库,比如ijson或者json-stream,它们都能处理类文件对象(比如subprocess的stdout),不需要把整个数组加载到内存。
以ijson为例,先安装库:
pip install ijson
然后解析tshark的JSON输出流:
import subprocess import ijson proc = subprocess.Popen( ["tshark", "-i", "eth0", "-T", "json"], stdout=subprocess.PIPE, binary=True # ijson需要二进制流 ) # 解析数组中的每个元素(每个数据包) for packet in ijson.items(proc.stdout, "item"): # 处理数据包 print(f"数据包长度: {packet.get('frame.len', 'N/A')}")
ijson会逐个提取数组里的item元素,也就是每个数据包的JSON对象,完美适配你的需求。你提到的NAYA库也是类似原理,同样可以用这种方式传入类文件对象(proc.stdout本身就是类文件对象)来解析。
方案3:手动用内置json模块实现流解析
如果不想依赖第三方库,也可以用Python内置的json.JSONDecoder的raw_decode方法手动处理流:
import subprocess import json proc = subprocess.Popen( ["tshark", "-i", "eth0", "-T", "json"], stdout=subprocess.PIPE, text=True ) decoder = json.JSONDecoder() buffer = "" for chunk in iter(lambda: proc.stdout.read(1024), ""): buffer += chunk while True: try: # 尝试解析buffer中的JSON obj, idx = decoder.raw_decode(buffer) # 如果是数组开头,跳过 if isinstance(obj, list): buffer = buffer[idx:] continue # 处理单个数据包对象 print(f"源端口: {obj.get('tcp.srcport', 'N/A')}") buffer = buffer[idx:] except ValueError: # 没有足够的字符完成解析,继续读下一块 break
这个方法需要自己处理缓冲区和数组的起始标记,代码稍微繁琐,但好处是不需要安装额外依赖,适合环境受限的场景。
内容的提问来源于stack exchange,提问作者WoJ

