【问题标题】:Add nodes & edges in graph via networkx and using python通过networkx和使用python在图中添加节点和边
【发布时间】:2015-07-05 12:41:49
【问题描述】:

我需要创建一个 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')
...

当我运行此代码时,我收到以下错误:

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

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)

我什至不知道我做错了什么。文档并没有说明太多,而且 网上所有的例子似乎都是用和我的代码一样的语法编写的。

【问题讨论】:

  • 请显示完整的回溯错误信息。
  • 能否提供parseOutput 变量的示例内容? nodeList = parseOutput 后跟 edgeList = parseOutput 在这里看起来很奇怪。
  • 我在代码上方显示的 IP 列表是 parseOutput 的确切值
  • @HappyLeapSecond 更新了完整的回溯错误消息

标签: python graph networkx scapy


【解决方案1】:

你看到的问题是由

引起的
IPList = [[] for i in range (20)]

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

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

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

回想起来,如果您仔细考虑错误消息 你可以看到它告诉你 n 有 0 个值需要解压。这使得 判断节点 n 是否为空列表:

In [136]: nn, ndict = []
ValueError: need more than 0 values to unpack

空列表来自parseOutput


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

IPList = [[] for i in range (20)]

在 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

这更容易,更易读,因为你不需要对索引大惊小怪 数字并增加一个计数器变量。此外,它允许您处理 pkts 中任意数量的项目,而无需首先知道 pkts.


需要修复的另一件事是nodeList 通常不是 与edgeList 相同。

如果您要声明nodeListnodeList 应该是 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'])

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

edgeList = parseOutput
g.add_edges_from(edgeList)

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()

产量


【讨论】:

  • 错误在于 parsePcap 吐出的内容和 parseOutput 应该采取的内容之间。如果我只是创建一个 IP 列表并将它们提供给 parseOutput,它似乎运行顺利。但是如果我使用我编写的模块 - parsePcap(),它的输出似乎有问题,我看到这个错误:
  • 'Traceback(最近一次调用最后):文件“test.py”,第 36 行,在 g.add_edges_from(edgeList) 文件“/usr/local/lib/python2.7/ dist-packages/networkx/classes/graph.py”,第 781 行,在 add_edges_from “边缘元组 %s 必须是 2 元组或 3 元组。”%(e,)) networkx.exception.NetworkXError: 边缘元组 [ ] 必须是 2 元组或 3 元组'
  • 啊哈。如果我在parseOutput 末尾包含一个空列表,我可以重现您的错误消息。请参阅最后一次编辑以获取 parsePcap 的替代版本。这将创建一个IPList,最后没有空列表。
  • +1 @HappyLeapSecond - 我在过去的某个时候确实使用了 append,但将其修改为当前的方式。将代码改回使用 append 作为添加 IP 边缘和节点的方式处理了我上次发布的错误。谢谢!
猜你喜欢
  • 1970-01-01
  • 2019-03-28
  • 2022-06-14
  • 2012-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多