PyQt实战——使用python提取JSON数据(十)

系类往期文章:
PyQt5实战------多脚本集合包,前言与环境配置(一)
PyQt5实战------多脚本集合包,UI以及工程布局(二)
PyQt5实战------多脚本集合包,程序入口QMainWindow(三)
PyQt5实战------操作台打印重定向,主界面以及stacklayout使用(四)
PyQt5实战------UTF-8编码器UI页面设计以及按钮连接(五)
PyQt5实战------UTF-8编码器功能的实现(六)
PyQt5实战------翻译器的UI页面设计以及代码实现(七)
PyQt5实战------翻译的实现,第一次爬取微软翻译经验总结(八)
PyQt5实战------翻译的实现,成功爬取微软翻译(可长期使用)经验总结(九)

前言

距离上次更新PyQt实战系列隔了好久,因为现实中比较忙,而且确实是存货已经用完,现在对脚本集合包更新了一些新的内容,包括:JSON数据的处理,ADPCM音频编解码,PCM二进制文件构建以及PCM音频播放功能,此外,还有一个数据加密解密算法,与笔者之前的文章《逆向工程实战,在反汇编工具中理解汇编与伪C》中的算法一致,是笔者在反汇编的学习中无意间发现的一种数据加密算法,简单且有效,当初逆向该算法时花了不少时间,总之,这些内容后续都会讲到!

JSON数据处理UI

本功能的UI设计十分简单,用到的全是PyQt5实战系列提及过的内容,因此本文将不再重复讲解UI界面的代码,但是代码依然会贴出来,如下:

python 复制代码
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtSvg import *

from component.btnStyle import *
from component.editStyle import *
from component.getPath import *
from tools.wiresharckJsonProcess import *


class WwiresharkJsonProc(QWidget):
    def __init__(self):
        super().__init__()
        self.filePaths = ['']
        self.initUI()

    def initUI(self):
        self.JsonProcesslayout = QVBoxLayout()
        self.setLayout(self.JsonProcesslayout)
        # 文件选择
        self.filelayout = QHBoxLayout()
        self.lable = QLabel("请选择文件",self)
        self.filelayout.addWidget(self.lable)
        self.input = QLineEdit(self)
        LineEditStyle(self.input)
        self.filelayout.addWidget(self.input)
        self.choosebtn = QPushButton("选择文件",self)
        btnReleaseStyleA(self.choosebtn)
        self.choosebtn.clicked.connect(self.getpath)
        self.filelayout.addWidget(self.choosebtn)
        self.JsonProcesslayout.addLayout(self.filelayout)
        
        # 开始处理
        self.exebtn = QPushButton("开始处理",self)
        btnReleaseStyleA(self.exebtn)
        self.exebtn.clicked.connect(self.exebtn_press_clicked)
        self.JsonProcesslayout.addWidget(self.exebtn)

    def getpath(self):
        get_path(self)
        self.input.setText(self.filePaths[0])
        
    def exebtn_press_clicked(self):
        processJson(self.filePaths[0])

界面非常简单,如下所示

可以看到,在这个页面下仅有一个文件选择的组件加上一个处理的按钮。非常简单的一个页面设计,本文的重点并不在这个UI设计上,而是在wireshark的抓包数据转换成JSON格式以及python提取JSON数据。

JSON数据的来源

本文所使用的JSON数据来源于wireshark抓包,wireshark是一个网络封包分析工具,可以截取各种网络数据包,并显示数据包中的各种详细信息,常用于开发测试过程中的问题定位。但笔者并不是用wireshark来处理网络封包,而是处理低功耗蓝牙(BLE)的封包。wireshark本身并没有捕获BLE数据包的能力,但是结合特殊的dongle可以,使用NRF52832 BLE Sniffer低功耗蓝牙抓包器可以捕捉到到低功耗蓝牙的空中数据,非常实用,感兴趣的同学可以在网上查询相关信息,本文不做赘述。

这里笔者对一个数据包做了筛选,如下图所示,从机通过notify的形式向主机传递消息,消息通过handle值为0x97的特征传递给主机,这里不了解蓝牙的同学可以不用理会,以后笔者会单独出一个蓝牙系列,分享笔者的蓝牙知识。

在下面详细信息中可以看到,所选中的这一条数据,是从机通过handle0x97的特征,向主机发送共计120个字节的value数据:3b 18 01 ....... 04 d1 1a,如果手动一条一条数据中蓝色框框的内容复制出来是非常耗时的,可以采用以下方式获取数据:

文件 → 导出分组解析结果 → As JSON

可以导出JSON格式的数据,我们展示一下JSON数据

json 复制代码
[
  {
    "_index": "packets-2024-12-06",
    "_type": "doc",
    "_score": null,
    "_source": {
      "layers": {
        "frame": {
          "frame.section_number": "1",
          "frame.interface_id": "0",
          "frame.interface_id_tree": {
            "frame.interface_name": "COM30-4.0",
            "frame.interface_description": "nRF Sniffer for Bluetooth LE COM30"
          },
          "frame.encap_type": "186",
          "frame.time": "Dec  6, 2024 11:19:43.491844000 中国标准时间",
          "frame.offset_shift": "0.000000000",
          "frame.time_epoch": "1733455183.491844000",
          "frame.time_delta": "0.000231000",
          "frame.time_delta_displayed": "0.000000000",
          "frame.time_relative": "62.812024000",
          "frame.number": "12534",
          "frame.len": "53",
          "frame.cap_len": "53",
          "frame.marked": "0",
          "frame.ignored": "0",
          "frame.protocols": "nordic_ble:btle:btl2cap:btatt"
        },
        "nordic_ble": {
          "nordic_ble.board_id": "30",
          "nordic_ble.header": {
            "nordic_ble.plen": "46",
            "nordic_ble.protover": "3",
            "nordic_ble.packet_counter": "36765",
            "nordic_ble.packet_id": "6"
          },
          "nordic_ble.len": "10",
          "nordic_ble.flags": "0x0d",
          "nordic_ble.flags_tree": {
            "nordic_ble.crcok": "1",
            "nordic_ble.direction": "0",
            "nordic_ble.encrypted": "1",
            "nordic_ble.micok": "1",
            "nordic_ble.phy": "0",
            "nordic_ble.flag_reserved7": "0"
          },
          "nordic_ble.channel": "29",
          "nordic_ble.rssi": "-45",
          "nordic_ble.event_counter": "1158",
          "nordic_ble.time": "1172995411",
          "nordic_ble.packet_time": "296",
          "nordic_ble.delta_time": "151",
          "nordic_ble.delta_time_ss": "231"
        },
        "btle": {
          "btle.access_address": "0x27353836",
          "btle.master_bd_addr": "90:e4:68:a8:41:7c",
          "btle.slave_bd_addr": "00:00:00:08:47:2c",
          "btle.data_header": {
            "btle.data_header.llid": "0x02",
            "btle.data_header.next_expected_sequence_number": "1",
            "btle.data_header.sequence_number": "0",
            "btle.data_header.more_data": "1",
            "btle.data_header.cte_info_present": "0",
            "btle.data_header.rfu": "0",
            "btle.data_header.length": "27"
          },
          "btle.length": "27",
          "btle.l2cap_index": "132",
          "btle.connection_parameters_in": "11696",
          "btle.crc": "0xe3cc46"
        },
        "btl2cap": {
          "btl2cap.length": "23",
          "btl2cap.cid": "0x0004"
        },
        "btatt": {
          "btatt.opcode": "0x1b",
          "btatt.opcode_tree": {
            "btatt.opcode.authentication_signature": "0",
            "btatt.opcode.command": "0",
            "btatt.opcode.method": "0x1b"
          },
          "btatt.handle": "0x0036",
          "btatt.handle_tree": {
            "btatt.service_uuid16": "0x1812"
          },
          "btatt.value": "60:d8:4b:d4:62:66:d9:d5:4c:d5:5f:d6:d3:5d:63:da:64:d7:61:d8"
        }
      }
    }
  },

这么长的数据,仅仅wireshark中展示的一条数据,而我们需要的数据,仅仅是btatt.value这一个属性

json 复制代码
"btatt.value": "60:d8:4b:d4:62:66:d9:d5:4c:d5:5f:d6:d3:5d:63:da:64:d7:61:d8"

而敏锐的同学可以发现,此JSON文件的开头,是[,也就是说,此JSON文件的框架是[{第一条数据},{第二条数据}....{第n条数据}...],这种格式非常适合python通过list数据结构进行处理。

JSON数据提取

先来观察我们需要的目标数据,btatt.value,这是由多层字典嵌套在其中的,因此要依次往上查找不同层级的字典,可以发现:

  • __source
  • layers
    • btatt
      • btatt.value

是这样的一个结构。

我们现在来看代码

python 复制代码
import json

def processJson(filename):
    with open(filename, "r", encoding="utf-8") as f:
        attvalue = json.load(f)
        for i in range(len(attvalue)):
            voicevalue = attvalue[i]["_source"]["layers"]["btatt"]["btatt.value"] + "\n"
            with open("workspaces/VoiceData.txt", "a", encoding="utf-8") as f:
                f.write(voicevalue)
        print("line len: ",len(voicevalue))
        print("line count: ",len(attvalue))
        # print(data)

我们来分析一下代码:

  • filename这个文件中读取数据,以utf-8编码格式解码
  • json.load(f)是指从f中读取数据JSON数据,解析并返回对应的Python对象(例如,字典,列表等,具体取决于JSON的结构),通过我们上面的分析,此json会被解析成python的列表(因为最外层是[])。
  • 循环读取attvalue列表对象
  • 读取attvallue列表中第i个元素中的layers字典中的btatt字典中的btatt.value所对应的值,并加上一个换行符/n,最后复制给voicevalue
  • voicevalue写进workspaces/VoiceData.txt文件的末尾,a表示在文件末尾写入东西,而不覆盖原来的内容。
  • 当将所有的内容都写完时,返回每条数据的数据量以及数据总量

该方法被单独写在wiresharckJsonProcess.py文件中,存放在tools目录下,被UI页面通过import以模块导入的形式使用。

总结

本文的内容并不复杂,主要是如何从wireshark中导出JSON数据,以及如何使用python对数据进行过滤和处理,JSON是非常常用的数据传输和保存格式尤其在网络中非常常用,因此熟练的掌握看懂和处理对程序员来说是值得的,而且并不难不是吗,祝你变得更强!

相关推荐
How_doyou_do12 分钟前
备战菊厂笔试4
python·算法·leetcode
(・Д・)ノ1 小时前
python打卡day27
开发语言·python
小oo呆2 小时前
【学习心得】Jupyter 如何在conda的base环境中其他虚拟环境内核
python·jupyter·conda
小白学大数据3 小时前
Scrapy框架下地图爬虫的进度监控与优化策略
开发语言·爬虫·python·scrapy·数据分析
浊酒南街3 小时前
TensorFlow之微分求导
人工智能·python·tensorflow
立秋67893 小时前
用Python绘制梦幻星空
开发语言·python·pygame
alpszero3 小时前
YOLO11解决方案之对象裁剪探索
人工智能·python·计算机视觉·yolo11
白云千载尽4 小时前
相机、雷达标定工具,以及雷达自动标定的思路
python·自动驾驶·ros
咕噜咕噜啦啦4 小时前
python爬虫实战训练
爬虫·python
盛夏绽放4 小时前
Python字符串常用内置函数详解
服务器·开发语言·python