使用Python进行数据爬取时,很多情况下需要登录或需要某些Cookie,如果直接从浏览器中复制Cookie的话每次都要重新复制,使用selenium比较慢,这样很麻烦。因此考虑使用Python抓包,这样的话每次只需要在程序运行后手动登录或点击一次,下面就可以自动进行了。
依赖的包
- scapy (用于抓包)
- dpkt (用于分析)
- socket (用于获取数据包的IP)
抓包代码
from scapy.sendrecv import sniff
from scapy.utils import wrpcap
import dpkt
import socket
ifs = 'Intel(R) Ethernet Connection (5) I219-LM' # 网卡
ip_dst = 'xx.xx.xx.xx' # 目标ip地址
d = sniff(iface=ifs, count=10)
wrpcap("demo.pcap", d) #保存为pcap文件
分析代码
可以使用dpkt或scapy中的rdpcap进行分析
scapy中rdpcap分析
d = rdpcap('demo.pcap')
res = []
for pkt in d.res:
try: # 只要应用层数据包,因此如果不包含应用层数据包则进入except
IP_pkt = pkt.payload # 获取IP层数据包
TCP_pkt = IP_pkt.payload # 获取TCP层数据包
Raw_pkt = TCP_pkt.payload # 获取应用层数据包
data = Raw_pkt.load # 获取包内具体数据
res.append(data.decode(errors='ignore')) # Bytes解码为str
except AttributeError:
pass
for r_i in range(len(res)):
# 上面得到的数据每一条都是不完整的,下面就是进行具体筛选和拼接
getIndex = res[r_i].find('*****这里放入筛选语句')
if getIndex != -1:
p_get = res[r_i][getIndex:-1]
count = 1
while res[r_i + count].find(r'HTTP/1.1 200 OK') == -1: # 直到遇到下一个数据包开头
p_get += res[r_i + count]
count += 1
break
dpkt分析
cookie = ''
with open("demo.pcap", "rb") as f:
pcap = dpkt.pcap.Reader(f)
for timestamp, buf in pcap:
eth = dpkt.ethernet.Ethernet(buf) # 获得以太包,即数据链路层包
if not isinstance(eth.data, dpkt.ip.IP): # 判断是否是网络层数据
continue
ip = eth.data
dst_ip = socket.inet_ntoa(ip.dst)
if dst_ip == ip_dst and isinstance(ip.data, dpkt.tcp.TCP): # 判断是否是传输层且是否符合目标IP(使用sniff过滤器也是一样的)
tcp = ip.data
try:
request = dpkt.http.Request(tcp.data) # 请求包
for key, value in request.headers.items(): # 请求头
if key == 'cookie':
cookie = value
print(f'找到Cookie = {cookie}')
except (dpkt.dpkt.NeedData, dpkt.dpkt.UnpackError):
continue
if cookie != '':
break
if cookie != '':
try:
# 这里放置测试采集代码
print('Cookie正确,开始采集数据')
break
except:
cookie = ''
print('Cookie不正确,继续获取')
全部代码
ifs = 'Intel(R) Ethernet Connection (5) I219-LM' # 网卡
ip_dst = 'xx.xx.xx.xx' # 目标ip地址
while 1:
d = sniff(iface=ifs, count=100)
wrpcap("demo.pcap", d) #保存为pcap文件
cookie = ''
with open("demo.pcap", "rb") as f:
pcap = dpkt.pcap.Reader(f)
for timestamp, buf in pcap:
eth = dpkt.ethernet.Ethernet(buf) # 获得以太包,即数据链路层包
if not isinstance(eth.data, dpkt.ip.IP): # 判断是否是网络层数据
continue
ip = eth.data
dst_ip = socket.inet_ntoa(ip.dst)
if dst_ip == ip_dst and isinstance(ip.data, dpkt.tcp.TCP): # 判断是否是传输层且是否符合目标IP
tcp = ip.data
try:
request = dpkt.http.Request(tcp.data) # 请求包
for key, value in request.headers.items(): # 请求头
if key == 'cookie':
cookie = value
print(f'找到Cookie = {cookie}')
except (dpkt.dpkt.NeedData, dpkt.dpkt.UnpackError):
continue
if cookie != '':
break
if cookie != '':
try:
# 这里放置测试采集代码
print('Cookie正确,开始采集数据')
break
except:
cookie = ''
print('Cookie不正确,继续获取')