Python多字符串精准匹配及SOAP数据包监控正则优化问题
我来帮你解决这两个问题,先从你当前遇到的SOAP监控匹配问题入手,再讲Python精准匹配多字符串的通用方案:
一、修复SOAP数据包的正则匹配问题并优化性能
你现在的核心问题是正则分组逻辑不对,加上重复编译正则导致性能浪费,咱们一步步调整:
1. 修正正则匹配逻辑
你原来的正则<ResponseCode>(.*?)<|<ResponseRunTime>(.*?)<是两个独立分支,每个分支单独捕获分组,所以findall会返回每个分支的匹配结果,就出现了[('0', ''), ('', '1763')]这种带空白值的情况。要拿到('0', '1763')的结果,推荐两种更合理的写法:
- 写法一:分别匹配两个标签(直观,性能稳定)
- 写法二:按固定顺序匹配两个标签(适合SOAP响应中标签顺序不变的场景)
2. 提前编译正则,避免重复开销
不要在回调函数里每次都编译正则——编译是耗时操作,提前编译好复用,能显著降低每秒处理110个包的性能损耗。
3. 修复Scapy过滤规则
你原来的tcp and port 186 or port 86逻辑有问题:它会匹配所有TCP且端口186的包,或者所有端口86的包(不管是不是TCP)。正确写法应该是tcp and (port 186 or port 86),确保只处理TCP协议下的目标端口。
4. 修改后的完整代码
from scapy.all import * import re # 提前编译正则,复用整个会话周期 # 写法一:分别编译两个标签的正则 code_pattern = re.compile(r'<ResponseCode>(.*?)<', re.DOTALL) runtime_pattern = re.compile(r'<ResponseRunTime>(.*?)<', re.DOTALL) # 写法二:按顺序匹配两个标签,一次性捕获(可选,适合标签顺序固定的场景) # combined_pattern = re.compile(r'<ResponseCode>(.*?)<.*?<ResponseRunTime>(.*?)<', re.DOTALL) def pack_callback(packet): if packet.haslayer(TCP) and packet[TCP].payload: # 优化payload处理:如果是字节类型,可直接用字节正则减少转换开销 payload = str(packet[TCP].payload) # 写法一:依次匹配两个标签 code_match = code_pattern.search(payload) runtime_match = runtime_pattern.search(payload) if code_match and runtime_match: result = (code_match.group(1), runtime_match.group(1)) print(result) # 输出('0', '1763') # 写法二:用组合正则一次性匹配(注释掉写法一可启用) # combined_match = combined_pattern.search(payload) # if combined_match: # print(combined_match.groups()) # 修复过滤规则+关闭冗余日志输出 sniff(filter='tcp and (port 186 or port 86)', prn=pack_callback, iface='vmxnet3 Ethernet Adapter', verbose=0)
5. 额外性能优化建议
针对每秒110个包的场景,再提几个小技巧:
- 减少回调里的IO操作(比如
print),如果需要记录数据,尽量批量写入或异步写入,避免阻塞。 - 如果只需要处理SOAP响应包,可以调整过滤规则为
tcp dst port 186 or tcp dst port 86(根据客户端实际端口调整),减少无关数据包的处理。 - 若遇到TCP分段的SOAP响应,可使用Scapy的TCP重组功能(或
scapy-http库),确保拿到完整的payload。
二、Python中精准匹配多个字符串的通用方法
根据不同场景,推荐这几种高效方案:
1. 正则表达式匹配(适合少量字符串)
用|分隔多个目标字符串,注意如果有包含关系的字符串,把长的放在前面(比如先匹配abcde再匹配abc),避免短字符串先匹配导致长串漏检:
import re targets = ['apple', 'banana', 'cherry'] # 用re.escape转义特殊字符,避免正则语法冲突 pattern = re.compile('|'.join(map(re.escape, targets)), re.IGNORECASE) text = "I like apple and banana" # 判断是否匹配 if pattern.search(text): print("匹配到目标字符串") # 获取所有匹配项 matches = pattern.findall(text)
2. Aho-Corasick算法(适合批量大量字符串)
如果需要匹配成百上千个字符串,正则性能会下降,Aho-Corasick是线性时间复杂度的算法,非常适合批量匹配,可使用pyahocorasick库:
import ahocorasick # 构建自动机 automaton = ahocorasick.Automaton() for idx, key in enumerate(['apple', 'banana', 'cherry']): automaton.add_word(key, (idx, key)) automaton.make_automaton() # 搜索文本中的所有匹配 text = "I like apple and banana" for end_idx, (idx, key) in automaton.iter(text): start_idx = end_idx - len(key) + 1 print(f"匹配到{key},位置:{start_idx}-{end_idx}")
3. 字符串方法结合any()(适合简单判断)
如果只是判断文本是否包含任意一个目标字符串,用any()最直观:
targets = ['apple', 'banana', 'cherry'] text = "I like apple" if any(target in text for target in targets): print("匹配到目标字符串")
内容的提问来源于stack exchange,提问作者Wu Rao
相关产品推荐
相关产品推荐

