通过networkx和使用python在图中添加节点和边

Nir*_*ras 2 python graph scapy networkx

我需要创建一个 IP 地址图并标记它们之间的边,我为此编写了下面的代码。列表,即 parseOutput() 的内容,看起来像这样:

('172.16.254.128', '216.58.208.206')
('216.58.208.206', '172.16.254.128')
('172.16.254.128', '216.58.208.226')
('216.58.208.226', '172.16.254.128')
('172.16.254.128', '8.8.8.8')
('8.8.8.8', '172.16.254.128')
('172.16.254.128', '216.58.208.227')
('172.16.254.128', '216.58.208.227')
('216.58.208.227', '172.16.254.128')
('172.16.254.128', '216.58.208.227')
('172.16.254.128', '216.58.208.227')
...
Run Code Online (Sandbox Code Playgroud)

当我运行此代码时,出现以下错误:

Traceback (most recent call last):
  File "test.py", line 40, in <module>
    g.add_nodes_from(nodeList)
  File "/usr/local/lib/python2.7/dist-packages/networkx/classes/graph.py", line 429, in add_nodes_from
    nn,ndict = n
ValueError: need more than 0 values to unpack
Run Code Online (Sandbox Code Playgroud)
import logging, sys, struct, binascii, socket
from scapy.all import *
import networkx as nx
import matplotlib.pyplot as plt

pkts=rdpcap("pcapFile.pcap",20)

def parsePcap():
        IPList = [[] for i in range (20)]
        count = 0
        for pkt in pkts:
                #print pkt.summary()
                if pkt.haslayer(IP):
                        #proto = pkt.getLayer(IP).proto
                        x = pkt.getlayer(IP).src
                        y = pkt.getlayer(IP).dst
                        IPList[count]= (x,y)
                        #IPList[count].append(proto)
                        print IPList[count]
                        count += 1
        return IPList


parseOutput = parsePcap()
nodeList = parseOutput
edgeList = parseOutput

g = nx.Graph()

g.add_nodes_from(nodeList)
print g.number_of_nodes
g.add_edges_from(edgeList)

pos = nx.spring_layout(g,scale=1) #default to scale=1
nx.draw(g,pos)
Run Code Online (Sandbox Code Playgroud)

我什至不知道我做错了什么。文档没有说明太多,所有在线示例似乎都是用与我的代码相同的语法编写的。

unu*_*tbu 5

您看到的问题是由

IPList = [[] for i in range (20)]
Run Code Online (Sandbox Code Playgroud)

这导致parsePcap()len(pkts)小于 20时返回一个带有空列表或列表末尾的序列列表:

parseOutput = [
('172.16.254.128', '216.58.208.206'),
...
('172.16.254.128', '216.58.208.227'),
[],  #<---------------- This is causing the problem 
]
Run Code Online (Sandbox Code Playgroud)

parseOutput传递给 时g.add_nodes_from,您会收到回溯错误消息:

File "/usr/local/lib/python2.7/dist-packages/networkx/classes/graph.py", line 429, in add_nodes_from
  nn,ndict = n
ValueError: need more than 0 values to unpack
Run Code Online (Sandbox Code Playgroud)

回想起来,如果您仔细考虑错误消息,您会发现它告诉您n有 0 个要解包的值。如果n节点是一个空列表,这是有道理的:

In [136]: nn, ndict = []
ValueError: need more than 0 values to unpack
Run Code Online (Sandbox Code Playgroud)

空列表来自parseOutput.


而不是预先分配固定大小的列表:

IPList = [[] for i in range (20)]
Run Code Online (Sandbox Code Playgroud)

在 Python 中执行此操作的首选方法是使用以下append方法:

def parsePcap():
    IPList = []
    for pkt in pkts:
        if pkt.haslayer(IP):
            x = pkt.getlayer(IP).src
            y = pkt.getlayer(IP).dst
            IPList.append((x, y))
    return IPList
Run Code Online (Sandbox Code Playgroud)

这更容易且更易读,因为您不需要大惊小怪的索引号和递增计数器变量。此外,它允许您处理任意数量的项目,pkts而无需首先知道 pkts.


需要修复的另一件事是nodeList通常与edgeList.

如果要声明 a nodeList,则nodeList应该是可迭代的 IP 地址,而 edgeList 应该是可迭代的元组,例如parseOutput

nodeList = set([item for pair in parseOutput for item in pair])
print(nodeList)
# set(['216.58.208.206', '216.58.208.227', '172.16.254.128',
#  '216.58.208.226', '8.8.8.8'])
Run Code Online (Sandbox Code Playgroud)

但是,由于 edgeList 中也提到了所有节点,因此您可以省略声明节点并使用

edgeList = parseOutput
g.add_edges_from(edgeList)
Run Code Online (Sandbox Code Playgroud)

g.add_edges_from 将隐式添加节点。


import matplotlib.pyplot as plt
import networkx as nx

parseOutput = [
('172.16.254.128', '216.58.208.206'),
('216.58.208.206', '172.16.254.128'),
('172.16.254.128', '216.58.208.226'),
('216.58.208.226', '172.16.254.128'),
('172.16.254.128', '8.8.8.8'),
('8.8.8.8', '172.16.254.128'),
('172.16.254.128', '216.58.208.227'),
('172.16.254.128', '216.58.208.227'),
('216.58.208.227', '172.16.254.128'),
('172.16.254.128', '216.58.208.227'),
('172.16.254.128', '216.58.208.227'),]

g = nx.Graph()
edgeList = parseOutput
g.add_edges_from(edgeList)

pos = nx.spring_layout(g,scale=1) #default to scale=1
nx.draw(g,pos, with_labels=True)
plt.show()
Run Code Online (Sandbox Code Playgroud)

产量

在此处输入图片说明