在python中解析大(.5Gb)pcap文件

时间:2015-09-12 04:49:23

标签: python list file pcap

我有一个大的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'),...

3 个答案:

答案 0 :(得分:1)

至少在您的问题的部分

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)

但是如果你只想暂时存储数组以在程序之间传递它,我建议不要编写自己的解析代码。尝试使用picklejson模块以更易于阅读的格式存储数据。

答案 1 :(得分:1)

另一件需要考虑的事情。您的输入文件是5Gb,因此您可能不应该从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 triple都已准备就绪,它会从函数返回,写入输出文件,然后从内存中处理掉。

通过使用生成器而不是构建列表并返回它,您将允许自己处理更大的文件。 5Gb小于大多数现代系统上的RAM量,因此输入文件不是真正的问题 - 但是如果你要处理500Gb文件,你会发现生成器版本比build-a-list快很多-and-return-it版本,它将不断访问交换文件。

答案 2 :(得分:1)

我对你报告的输出感到有点困惑,因为我认为它不可能(换行符和一些尾随的逗号似乎来自哪里)。但是,我想我理解你的代码中出了什么问题。

如果我理解正确,您需要将(source, destination, protocol)三元组写入文件,然后稍后将其读回并打印出源IP地址和目标IP地址(或者对它们执行某些操作,无论如何)。

您遇到的问题是您在元组本身上调用了str,这意味着您将获得混淆后续处理代码的输出。具体而言,您在map中拨打的write电话不合适。

你可能想要" ".join(",".join(map(str, tup)) for tup in parsePcap()。这将格式化像121.14.142.72,0.32.59.21,6这样的元组(没有括号和引号)。此外,它将按空格分隔多个元组,因此示例输出中的三个元组将被写入您的文件:

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

您的解析代码也需要一个小的更新。目前你正在分割空白,但随后处理结果就好像你会得到元组一样。在您能够处理单独的项目之前,您需要再次(在逗号上)拆分:

with open("filename") as f:
    myArr = [i.split(',') for i in f.readline().split()]

我在这里改变了很多东西。 with语句打开文件,确保之后再次关闭。该列表是使用列表推导创建的,它迭代从文件中读取的空格分隔的子串并拆分每个子串,以便在第一个脚本中返回与parsePcap返回的几乎相同的内容(不完全相同) ,内部值是列表而不是元组,协议是字符串而不是int)。

您正在执行的stripmap(str, ...)调用是完全没必要的(split没有参数会忽略前导和尾随空格,并且您从文件中读取的所有值都是字符串已经存在)