在 python 中解析大型 (.5Gb) pcap 文件
Parse large (.5Gb) pcap file in python
我有一个大的 pcap 文件,我正在使用下面的 python 代码进行解析。该代码有效,但存在问题。当我在下面的代码中看到解析 pcap 文件时,我将值存储在另一个名为 filename
的文件中
pkts=rdpcap("MyFile.pcap")
def parsePcap():
IPList = []
for pkt in pkts:
if IP in pkt:
ip_src=pkt[IP].src
ip_dst=pkt[IP].dst
ip_proto=pkt[IP].proto
IPList.append((ip_src,ip_dst,ip_proto))
return IPList
#parseOutput = parsePcap()
f = open('filename', 'w')
f.write(' '.join(map(str, parsePcap())))
f.close()
当我从 "filename" 检索值时出现问题。我得到以下输出(下面的确切示例)。但事实并非如此。
('121.14.142.72',
'0.32.59.21',
6,
)
('123.152.135.217',
'0.3.17.121',
17,
)
('71.229.65.158',
'0.48.101.12',
17,
)
当我运行下面的代码-
uniqueNodePairs=[]
myArr = map(str, open("filename").readline().strip().split())
for i in myArr:
print i
uniqueNodePairs.append((i[0],i[1]))# pairs of src., dst
for i in uniqueNodePairs:
print i
我得到以下信息 -
('(', "'")
("'", '0')
('6', ')')
('(', "'")
("'", '0')
('1', '7')
('(', "'")
("'", '0')
这意味着这些值不会存储为字符串,而是单个字符。这不是我想要的。我想要这样的输出
('121.14.142.72','0.32.59.21'),
('123.152.135.217','0.3.17.121'),...
这是您问题的 部分 ,至少:
myArr = map(str, open("filename").readline().strip().split())
当您在这里调用 readline()
时,您只会阅读一行。
要修复该特定行,您可能需要:
map(lambda x: str(x.strip().split()), open("filename").readlines())
但这并不能解决您的全部问题。您想要生成如下所示的文件:
('121.14.142.72','0.32.59.21',6)
('123.152.135.217','0.3.17.121',17)
以便正确阅读它们。
为什么不尝试这样的事情呢?
with open("filename", 'w') as f:
for i in parsePcap():
f.write("('%s','%s',%d)\n" % i)
但是如果你只是想临时存储数组以便在程序之间传递它,我建议不要编写自己的解析代码。尝试使用 pickle
或 json
模块以更易于阅读的格式存储您的数据。
另一件事要考虑。您的输入文件是 5Gb,因此您可能不应该 returning 来自 parsePcap() 函数的列表。由于您对该列表所做的一切都是对其进行迭代,因此最好使用 yield
关键字将您的函数转换为生成器。这是您的原始函数:
def parsePcap():
IPList = []
for pkt in pkts:
if IP in pkt:
ip_src=pkt[IP].src
ip_dst=pkt[IP].dst
ip_proto=pkt[IP].proto
IPList.append((ip_src,ip_dst,ip_proto))
return IPList
下面是生成器的样子:
def parsePcap():
for pkt in pkts:
if IP in pkt:
ip_src=pkt[IP].src
ip_dst=pkt[IP].dst
ip_proto=pkt[IP].proto
yield (ip_src,ip_dst,ip_proto)
这样,您永远不会将整个列表存储在内存中:当每个 src、dst、proto 三元组准备就绪时,它会从函数中得到 returned,写到您的输出文件中,然后从内存中处理掉。
通过使用生成器而不是构建列表并 returning 它,您将允许自己处理更大的文件。 5Gb 小于大多数现代系统上的 RAM 量,因此输入文件不是真正的问题——但如果你有一个 500Gb 的文件要处理,你会发现生成器版本比构建列表快得多-and-return-it 版本,它会不断地访问交换文件。
我对你报告得到的输出有点困惑,因为我认为这是不可能的(换行符和一些尾随逗号似乎不知从何而来)。不过,我想我明白你的代码出了什么问题。
如果我理解正确的话,你需要将 (source, destination, protocol)
三元组写到一个文件中,然后再读回它们并打印出源和目标 IP 地址(或者对它们做些什么) , 无论如何).
您遇到的问题是您在元组本身上调用 str
,这意味着您得到的输出会混淆您以后的处理代码。具体来说,您在 write
中进行的 map
调用是不合适的。
你可能想要 " ".join(",".join(map(str, tup)) for tup in parsePcap()
。这会将元组格式化为 121.14.142.72,0.32.59.21,6
(没有括号和引号)。此外,它将多个元组分隔 spaces,因此示例输出中的三个元组将写入您的文件:
121.14.142.72,0.32.59.21,6 123.152.135.217,0.3.17.121,17 71.229.65.158,0.48.101.12,17
您的解析代码也需要小幅更新。目前你在 whitespace 上拆分,但随后处理结果就好像你会取回元组一样。在您能够处理单独的项目之前,您需要再次拆分(在逗号上):
with open("filename") as f:
myArr = [i.split(',') for i in f.readline().split()]
我在这里改变了很多东西。 with
语句打开文件并确保它在之后再次关闭。该列表是使用列表理解创建的,它遍历从文件中读取的 space 分隔的子字符串并拆分每个子字符串,以便您返回几乎与第一个 parsePcap
返回的内容相同的内容脚本(不完全是,内部值是列表而不是元组,协议是字符串而不是 int)。
您所做的 strip
和 map(str, ...)
调用完全没有必要(split
没有参数会忽略前导和尾随白色 space,以及您读取的所有值文件中已经是字符串了)。
我有一个大的 pcap 文件,我正在使用下面的 python 代码进行解析。该代码有效,但存在问题。当我在下面的代码中看到解析 pcap 文件时,我将值存储在另一个名为 filename
的文件中pkts=rdpcap("MyFile.pcap")
def parsePcap():
IPList = []
for pkt in pkts:
if IP in pkt:
ip_src=pkt[IP].src
ip_dst=pkt[IP].dst
ip_proto=pkt[IP].proto
IPList.append((ip_src,ip_dst,ip_proto))
return IPList
#parseOutput = parsePcap()
f = open('filename', 'w')
f.write(' '.join(map(str, parsePcap())))
f.close()
当我从 "filename" 检索值时出现问题。我得到以下输出(下面的确切示例)。但事实并非如此。
('121.14.142.72',
'0.32.59.21',
6,
)
('123.152.135.217',
'0.3.17.121',
17,
)
('71.229.65.158',
'0.48.101.12',
17,
)
当我运行下面的代码-
uniqueNodePairs=[]
myArr = map(str, open("filename").readline().strip().split())
for i in myArr:
print i
uniqueNodePairs.append((i[0],i[1]))# pairs of src., dst
for i in uniqueNodePairs:
print i
我得到以下信息 -
('(', "'")
("'", '0')
('6', ')')
('(', "'")
("'", '0')
('1', '7')
('(', "'")
("'", '0')
这意味着这些值不会存储为字符串,而是单个字符。这不是我想要的。我想要这样的输出
('121.14.142.72','0.32.59.21'),
('123.152.135.217','0.3.17.121'),...
这是您问题的 部分 ,至少:
myArr = map(str, open("filename").readline().strip().split())
当您在这里调用 readline()
时,您只会阅读一行。
要修复该特定行,您可能需要:
map(lambda x: str(x.strip().split()), open("filename").readlines())
但这并不能解决您的全部问题。您想要生成如下所示的文件:
('121.14.142.72','0.32.59.21',6)
('123.152.135.217','0.3.17.121',17)
以便正确阅读它们。
为什么不尝试这样的事情呢?
with open("filename", 'w') as f:
for i in parsePcap():
f.write("('%s','%s',%d)\n" % i)
但是如果你只是想临时存储数组以便在程序之间传递它,我建议不要编写自己的解析代码。尝试使用 pickle
或 json
模块以更易于阅读的格式存储您的数据。
另一件事要考虑。您的输入文件是 5Gb,因此您可能不应该 returning 来自 parsePcap() 函数的列表。由于您对该列表所做的一切都是对其进行迭代,因此最好使用 yield
关键字将您的函数转换为生成器。这是您的原始函数:
def parsePcap():
IPList = []
for pkt in pkts:
if IP in pkt:
ip_src=pkt[IP].src
ip_dst=pkt[IP].dst
ip_proto=pkt[IP].proto
IPList.append((ip_src,ip_dst,ip_proto))
return IPList
下面是生成器的样子:
def parsePcap():
for pkt in pkts:
if IP in pkt:
ip_src=pkt[IP].src
ip_dst=pkt[IP].dst
ip_proto=pkt[IP].proto
yield (ip_src,ip_dst,ip_proto)
这样,您永远不会将整个列表存储在内存中:当每个 src、dst、proto 三元组准备就绪时,它会从函数中得到 returned,写到您的输出文件中,然后从内存中处理掉。
通过使用生成器而不是构建列表并 returning 它,您将允许自己处理更大的文件。 5Gb 小于大多数现代系统上的 RAM 量,因此输入文件不是真正的问题——但如果你有一个 500Gb 的文件要处理,你会发现生成器版本比构建列表快得多-and-return-it 版本,它会不断地访问交换文件。
我对你报告得到的输出有点困惑,因为我认为这是不可能的(换行符和一些尾随逗号似乎不知从何而来)。不过,我想我明白你的代码出了什么问题。
如果我理解正确的话,你需要将 (source, destination, protocol)
三元组写到一个文件中,然后再读回它们并打印出源和目标 IP 地址(或者对它们做些什么) , 无论如何).
您遇到的问题是您在元组本身上调用 str
,这意味着您得到的输出会混淆您以后的处理代码。具体来说,您在 write
中进行的 map
调用是不合适的。
你可能想要 " ".join(",".join(map(str, tup)) for tup in parsePcap()
。这会将元组格式化为 121.14.142.72,0.32.59.21,6
(没有括号和引号)。此外,它将多个元组分隔 spaces,因此示例输出中的三个元组将写入您的文件:
121.14.142.72,0.32.59.21,6 123.152.135.217,0.3.17.121,17 71.229.65.158,0.48.101.12,17
您的解析代码也需要小幅更新。目前你在 whitespace 上拆分,但随后处理结果就好像你会取回元组一样。在您能够处理单独的项目之前,您需要再次拆分(在逗号上):
with open("filename") as f:
myArr = [i.split(',') for i in f.readline().split()]
我在这里改变了很多东西。 with
语句打开文件并确保它在之后再次关闭。该列表是使用列表理解创建的,它遍历从文件中读取的 space 分隔的子字符串并拆分每个子字符串,以便您返回几乎与第一个 parsePcap
返回的内容相同的内容脚本(不完全是,内部值是列表而不是元组,协议是字符串而不是 int)。
您所做的 strip
和 map(str, ...)
调用完全没有必要(split
没有参数会忽略前导和尾随白色 space,以及您读取的所有值文件中已经是字符串了)。