PyShark 是一个Python库,它提供了一个方便的接口来使用Wireshark的命令行工具tshark进行包解析。它是基于Wireshark开发的,,你可以直接在Python中利用Wireshark强大的解析器处理捕获文件或实时数据流。但是网上对使用pyshark来分析http流量的说明文章太少,于是手动记录下。
pyshark的基础使用
1. 安装
1‑1. 先确保你已安装 Wireshark / tshark
1 | # Debian/Ubuntu |
注意:在 Linux 上,你可能需要把当前用户加入
wireshark
组或使用sudo
执行 tshark。
1‑2. 安装 PyShark
1 | pip install pyshark |
如果你想要支持更高版本的 tshark,建议先更新 Wireshark,然后再安装/升级 pyshark。
2. 基本概念
对象 | 含义 |
---|---|
FileCapture |
从已有 .pcap/.pcapng 文件读取包 |
LiveCapture |
在指定网络接口上实时捕获包 |
Packet |
单个协议帧/数据包/数据报,提供访问字段的方法 |
Layer |
协议层(Ethernet、IP、TCP 等),可通过属性或字典方式访问 |
3.基本使用
FileCapture
与LiveCapture
的读取方法
1 | import pyshark |
代码说明,通过pyshark.FileCapture
和pyshark.LiveCapture
获得的 capture的变量是一个FileCapture对象,我们可以里理解为被pyshark的流量包文件对象。而代码中pkt变量是一个Packet对象可以理解为流量包文件每一个的每一个流量包。而流量包的读取顺序则是和 Wireshark中No.
的顺序是相似的(在通过 display_filter过滤后流量包的读取顺序再用索引下标读取的话pyshark会对流量包重新排序)。
而且pyshark.FileCapture
和pyshark.LiveCapture
通常情况下我们只需要input_file
指定文件或interface
指定对应网卡,就可以分析到流量包。但为了分析方便开发者加了扩展参数来自进行分析,我对pyshark.FileCapture
和pyshark.LiveCapture
的常见的参数/扩展参数总结如下:
参数 | 作用 | 默认值 | 使用建议 / 注意事项 |
---|---|---|---|
keep_packets | 是否在读取后保留已读的包对象。 True → 内存中保存所有 Packet ;False → 只返回一个包,随后被 GC 回收。 |
True | 大文件(GB+)时建议设为 False,以防内存爆炸。 |
input_file | 指定要读取的捕获文件或 XML 可直接传入路径字符串、Path 对象或已打开的文件句柄( io.BufferedReader )。 |
None (必须提供) | 只在 FileCapture 中使用;若为文件句柄,tshark 会从当前位置开始读。 |
ring_file_size | 循环文件大小(kB) 当使用 output_file 或开启循环写入时,tshark 会把抓到的包写成一系列 “环形” 文件。 |
1024 kB (1 MiB) | 对高流量捕获建议增大;过小会导致文件频繁切换、磁盘 I/O 增加。 |
num_ring_files | 循环文件数量 保留的文件数,tshark 会在此数目后循环覆盖旧文件。 |
1 | 典型场景:想把最近 5 MiB 数据保存下来,只需 num_ring_files=5 。 |
ring_file_name | 循环文件基础名 实际写出的文件会以 <name>.0 , <name>.1 , … 命名。 |
/tmp/pyshark.pcap |
在 Windows 建议改为 C:\\temp\\pyshark.pcap ,避免路径中的斜杠被误解析。 |
interface | 抓包的网卡名称 如果不指定,tshark 会自动选第一个可用接口。 |
第一个可用接口 | 对多网卡机器一定要明确写 interface='eth0' 或者 en0 (macOS)。 |
bpf_filter | BPF 过滤器(Berkeley Packet Filter) 在捕获层面就筛选掉不需要的包,速度快。 |
None | 示例:bpf_filter='tcp port 80' ;注意:BPF 与 Wireshark 的显示过滤不同。 |
display_filter | Wireshark 显示过滤(tshark 层面的 -Y )在解析后再筛选,功能更强大但开销较大。 |
None | 示例:display_filter='http.request' ;如果你只需要 IP/TCP/UDP 信息,可把它留空或使用 BPF。 |
only_summaries | 仅生成包摘要 不解析完整协议层,速度快且内存占用低。 |
False | 对日志收集、流量计数非常合适;但无法获取字段值,只能拿到 pkt.summary 。 |
disable_protocol | 禁用某个协议的检测(tshark > 2) 可加速解析,尤其是你知道不需要某些大协议时。 |
None | 用法:disable_protocol='ssl' ;如果禁用了错误协议,后续访问会报错。 |
decryption_key | 对加密流量进行解密 用于 Wi-Fi 或 VPN 等加密捕获。 |
None | 需要对应 encryption_type ;若未正确设置,tshark 会忽略此字段。 |
encryption_type | 指定加密标准 必须是 'WEP' , 'WPA-PWD' , 或 'WPA-PWK' (默认 WPA-PWK)。 |
'WPA-PWK' |
与 decryption_key 配合使用;若不匹配,解密失败。 |
tshark_path | tshark 可执行文件的完整路径 如果系统 PATH 中没有 tshark 或你想指定特定版本。 |
自动搜索 | 在 Windows 上常用:r'C:\Program Files\Wireshark\tshark.exe' 。 |
output_file | 把抓到的数据写入文件(可与 ring_file_* 配合)即使你不想保存,也可以把它设为 None 或省略。 |
None | 若同时指定了 ring_file_name ,tshark 会将数据写成环形;否则直接写一个普通 pcap 文件。 |
Packet对象
再说回Packet对象,一个Packet本质上就对应一个流量包,在pyshark中提供了如下基础方法:
layers
: 获取数据包Packe所有的协议get_multiple_layers(layer_name)
: 获取数据包中指定名称的多个层(例如,一个数据包中可能有多个IP层)get_raw_packet()
: 获取原始的字节数据包highest_layer
: 返回数据包的最高协议层(例如,应用层协议名称)pretty_print()
: 以美观的格式打印数据包详情show()
: 类似于pretty_print()
,用于显示数据包详情sniff_time
: 数据包被捕获的时间戳transport_layer
: 返回传输层协议(如TCP或UDP)
Layer对象
这样我们从Packet对象获得到Layer对象,Layer对象对应会根据协议的不同,给我们提供不同的方法。比如TCP Layer协议对象会给我们提供:
srcport
: 源端口号dstport
: 目标端口号port
: 可能是源端口或目标端口(取决于上下文)seq
: 序列号(可能经过相对处理)seq_raw
: 原始序列号ack
: 确认号(可能经过相对处理)ack_raw
: 原始确认号nxtseq
: 下一个序列号stream
: TCP流索引(等同于Wireshark中的tcp.stream
)checksum
: 校验和checksum_status
: 校验和状态len
: TCP段长度hdr_len
: TCP头部长度time_relative
: 相对于第一个数据包的时间time_delta
: 与前一个数据包的时间差analysis
: 分析信息completeness
: 连接完整性状态
而IP Layer 协议会给我们提供ipv4相关网络成相关的协议的方法(ps:如果是ipv6 则是IPV6 Layer ,在pyshark中这里有区分的):
src
: 源IP地址dst
: 目标IP地址addr
: 可能是源或目标IP地址(取决于上下文)dst_host
: 目标主机地址version
: IP版本(通常是4或6)hdr_len
: IP头部长度dsfield
: 区分服务字段(DS Field)dsfield_dscp
: 差分服务代码点(DSCP)dsfield_ecn
: 显式拥塞通知(ECN)len
: IP数据包总长度id
: 标识字段(用于分片和重组)flags
: 标志位
pyshark分析http流量
同样pyshark的提供了HTTP Layer
的方法来对http流量进行分析。常见的方法如下:
用途 | 属性方法 | 结果示例 |
---|---|---|
请求方法 | request_method |
GET , POST |
完整 URI | request_full_uri |
https://example.com/api?x=1 |
URI 片段 | request_uri |
/api?x=1 |
HTTP 版本 | request_version / response_version |
HTTP/1.1 |
状态码 | response_code |
200 |
响应文本 | response_phrase |
OK |
内容类型 | content_type |
application/json |
Cookie | cookie_pair / set_cookie |
sessionid=abc123; ... |
在抓取 HTTP 流量时,需要注意 请求包 与 响应包 的区别。PyShark 在读取 HTTP 包时,只是粗略地保留了一些属性,并没有为它们做出专门的区分。因此,如果你在遍历包时对一个请求包使用了仅存在于响应包中的属性(例如 response_code
、response_phrase
),就会导致报错。
解决办法很简单:
- 请求包 具有
request_method
属性; - 响应包 具有
response_code
属性。
先根据这两个标识判断包的类型,再使用对应的属性进行处理,就能避免错误。
另一个常见需求是提取 HTTP 包中的主体数据:
- 对于请求包,获取的是请求体(body);
- 对于响应包,获取的是返回体(body)。
在处理时同样需要先区分包类型,然后再调用相应的属性或方法来读取主体内容。
常见的方法是对读取file_data
来进行处理,但是file_data默认是十六进制的数据需要对数据进行处理。但file_data
默认是16进制字符,对于pkt[‘DATA-TEXT-LINES’]的layer来获得body内容,而且代码只需要如下小部分,但是pkt[‘DATA-TEXT-LINES’]一班只在返回包里存在:
1 | if hasattr(pkt, 'DATA-TEXT-LINES'): |
最后,为了方便理解我写了一个安顺序遍历http流量的样例。
1 | #!/usr/bin/env python3 |