Python抓包利器:pcapy库从入门到实战详解
目录导读
pcapy是什么?为什么选择它进行抓包?
pcapy 是一个轻量级的Python库,它封装了Unix/Linux下的libpcap库(以及Windows下的WinPcap),如果你需要在Python环境中直接捕获网络数据包,pcapy是最底层的选择之一,它让你能够直接操作网络接口,抓取原始的二层到四层数据包。

优势对比:
- 比Scapy更轻量,不依赖大型包解析器
- 底层控制力强,适合做网络监控工具
- 与Wireshark使用的libpcap兼容
问:pcapy与Scapy、pyshark有什么区别?
答:Scapy更偏向协议构造与模糊测试,pyshark则依赖Wireshark完成解析,pcapy只负责抓取原始字节流,你需要自行处理协议解析,但也因此获得最高性能。
环境搭建与安装指南
1 系统依赖
- Windows: 下载并安装 Npcap 或 WinPcap
- Linux:
sudo apt install libpcap-dev(Debian/Ubuntu) - macOS:
brew install libpcap
2 Python安装
pip install pcapy
如果你使用Python 3.10+,建议使用最新版,部分旧版本可能不兼容。
问:安装失败提示“找不到pcap.h”怎么办?
答:这是典型的环境问题,在Ubuntu上执行sudo apt install python3-dev libpcap-dev,然后重新安装即可。
核心API详解与实战代码
1 列出可用网卡
import pcapy
print(pcapy.findalldevs())
# 输出类似: ['eth0', 'lo', 'wlan0', '\\Device\\NPF_{...}']
2 打开网卡并开始抓包
# 打开eth0,设置抓包大小为65535字节(完整包),混杂模式开启,超时1000ms
cap = pcapy.open_live('eth0', 65535, True, 1000)
# 设置过滤器:只抓取TCP端口80的数据
cap.setfilter('tcp port 80')
# 回调函数处理每个数据包
def packet_handler(header, data):
print(f"捕获到{len(data)}字节的数据包")
print(data[:20].hex()) # 显示前20字节十六进制
# 开始循环抓包,count=10表示抓取10个包后停止
cap.loop(10, packet_handler)
问:为什么setfilter无效?
答:过滤器语法遵循BPF(Berkeley Packet Filter)规则,可以用tcpdump -i eth0测试过滤器有效性,打开网卡时混杂模式必须为True才能看到所有流量。
如何用pcapy完成一次完整抓包?
场景:捕获本机HTTP请求并打印源IP和目的端口,下面给出完整代码:
import pcapy
import struct
def eth_frame(data):
# 解析以太网帧头前14字节
dst_mac = data[:6]
src_mac = data[6:12]
ether_type = struct.unpack('!H', data[12:14])[0]
return dst_mac, src_mac, ether_type, data[14:]
def ip_packet(data):
# 解析IP头部(标准20字节)
version_ihl = data[0]
ihl = version_ihl & 0x0F
src_ip = data[12:16]
dst_ip = data[16:20]
protocol = data[9]
return src_ip, dst_ip, protocol, data[ihl*4:]
def tcp_packet(data):
# 解析TCP头部
src_port = struct.unpack('!H', data[0:2])[0]
dst_port = struct.unpack('!H', data[2:4])[0]
return src_port, dst_port
def callback(header, data):
dst_mac, src_mac, ether_type, ip_data = eth_frame(data)
if ether_type != 0x0800: # 只处理IPv4
return
src_ip, dst_ip, protocol, tcp_data = ip_packet(ip_data)
if protocol != 6: # 只处理TCP
return
src_port, dst_port = tcp_packet(tcp_data)
# 格式化IP地址
src_ip_str = '.'.join(map(str, src_ip))
dst_ip_str = '.'.join(map(str, dst_ip))
if dst_port == 80 or src_port == 80:
print(f"HTTP流量: {src_ip_str}:{src_port} -> {dst_ip_str}:{dst_port}")
if __name__ == '__main__':
cap = pcapy.open_live('eth0', 65535, True, 100)
cap.setfilter('tcp port 80')
print("开始抓包(按Ctrl+C停止)...")
try:
cap.loop(0, callback) # 0表示无限循环
except KeyboardInterrupt:
print("停止抓包")
问:为什么我的代码抓不到包?
答:首先确认网卡名称正确,可以用findalldevs()列出,其次检查是否有root权限(Linux下需要sudo),最后用浏览器访问一个HTTP网站(非HTTPS)测试,HTTPS流量端口是443,需修改过滤器。
常见问题与答案(FAQ)
Q1:pcapy能否解析HTTPS数据包?
A:pcapy只能捕获加密后的字节流,无法解密HTTPS,要解析HTTPS需结合TLS密钥或使用中间人代理。
Q2:抓包速度慢怎么办?
A:使用pcapy.open_live()的最后一个参数设置超时时间(单位毫秒),减少内核态切换,同时确保过滤器在网卡层生效,减少应用层处理次数。
Q3:如何保存到.pcap文件?
A:pcapy不直接支持写文件,但可以使用pcapy.dump_open()创建转储对象,或者使用scapy.rdpcap()结合pcapy实现,最简方式是把data写入二进制文件。
Q4:Windows下怎么列出网卡?
A:pcapy.findalldevs()会返回类似\Device\NPF_{GUID}的字符串,需要使用管理员权限运行,也可以使用pcexcel插件辅助。
性能优化与注意事项
1 性能优化要点
- 缓冲区大小:
open_live()第一个参数设为65535(最大MTU) - 超时设置:设100-1000ms,避免频繁上下文切换
- 过滤器优先级:BPF过滤器越精确,内核丢掉的数据包越多,应用层负担越轻
- 多线程处理:回调函数尽量避免I/O操作,如写文件,应放入队列异步处理
2 安全注意事项
- Linux下必须使用root权限(
sudo python script.py) - Windows下需要管理员身份运行
- 只抓取你拥有权限的网络接口,尊重隐私和法律
3 与其他库的组合使用
# 用pcapy抓包 + scapy解析
from scapy.all import IP, TCP, Ether
def scapy_callback(header, data):
packet = Ether(data)
if IP in packet and TCP in packet and packet[TCP].dport == 80:
print(f"Scapy解析: {packet[IP].src} -> {packet[IP].dst}")
这种方式既保留了pcapy的高性能抓包能力,又利用了Scapy丰富的协议解析功能。
pcapy作为Python生态中的原始抓包库,虽然API简单到只包含几十行核心代码,但正是这种简单赋予了它极高的灵活性,无论是开发网络监控工具、入侵检测系统,还是进行协议分析,掌握pcapy都能让你获得底层网络数据的完全控制权,建议读者从本节提供的HTTP抓包代码开始,逐步添加DNS、ARP等协议解析,构建属于自己的抓包工具链。
标签: Python抓包