如何使用Python中的ElementTree从nmap XML输出获取特定供应商的IP地址

1 投票
2 回答
1590 浏览
提问于 2025-04-17 21:42

我想用来自nmap的XML输出,来获取在主机上运行的可达虚拟机的IP地址。这个输出是通过命令nmap -oX output.xml -sP 192.168.2.*获得的。我想找出每台机器的IP地址,前提是它们的厂商是QEMU Virtual NIC。为此,我选择使用Python的ElementTree XML API,但我在提取带有指定地址元素的主机元素时遇到了一些困难。

这里有一段要使用的XML输出示例:

<host><status state="up" reason="arp-response"/>
<address addr="192.168.2.93" addrtype="ipv4"/>
<address addr="52:54:00:E2:17:31" addrtype="mac" vendor="QEMU Virtual NIC"/>
<hostnames>
</hostnames>
<times srtt="1023" rttvar="5000" to="100000"/>
</host>
<host><status state="up" reason="arp-response"/>
<address addr="192.168.2.96" addrtype="ipv4"/>
<address addr="52:54:00:45:86:8A" addrtype="mac" vendor="QEMU Virtual NIC"/>
<hostnames>
</hostnames>
<times srtt="155" rttvar="5000" to="100000"/>
</host>
<host><status state="up" reason="arp-response"/>
<address addr="192.168.2.103" addrtype="ipv4"/>
<address addr="52:54:00:61:7A:E5" addrtype="mac" vendor="QEMU Virtual NIC"/>
<hostnames>
</hostnames>
<times srtt="391" rttvar="5000" to="100000"/>
</host>

我使用了findall和下面的XPath语法,找到了带有所需厂商属性的地址元素:

import xml.etree.ElementTree as ET
tree = ET.parse('output.xml')
tree.findall("./host/address/[@vendor='QEMU Virtual NIC']")

但我真正想要的是拥有上述地址元素的主机元素,这样我就可以找到同一主机的其他类型为“ipv4”的地址子元素,最终得到主机的IP地址。有没有人能告诉我如何使用XPathElementTree来实现这个目标?

2 个回答

2

主机:

./host[address[@vendor="QEMU Virtual NIC"]]

IPv4地址:

./host[address[@vendor="QEMU Virtual NIC"]]/address[@addrtype="ipv4"]/@addr

使用 lxml 进行交互:

>>> from lxml import etree
>>> doc = etree.XML("""<doc><host><status state="up" reason="arp-response"/>
... <address addr="192.168.2.93" addrtype="ipv4"/>
... <address addr="52:54:00:E2:17:31" addrtype="mac" vendor="QEMU Virtual NIC"/>
... <hostnames>
... </hostnames>
... <times srtt="1023" rttvar="5000" to="100000"/>
... </host>
... <host><status state="up" reason="arp-response"/>
... <address addr="192.168.2.96" addrtype="ipv4"/>
... <address addr="52:54:00:45:86:8A" addrtype="mac" vendor="QEMU Virtual NIC"/>
... <hostnames>
... </hostnames>
... <times srtt="155" rttvar="5000" to="100000"/>
... </host>
... <host><status state="up" reason="arp-response"/>
... <address addr="192.168.2.103" addrtype="ipv4"/>
... <address addr="52:54:00:61:7A:E5" addrtype="mac" vendor="QEMU Virtual NIC"/>
... <hostnames>
... </hostnames>
... <times srtt="391" rttvar="5000" to="100000"/>
... </host></doc>""")
>>> doc.xpath('./host[address[@vendor="QEMU Virtual NIC"]]')
[<Element host at 0xb72c0af4>, <Element host at 0xb72c0b1c>, <Element host at 0xb72c0b44>]
>>> doc.xpath('./host[address[@vendor="QEMU Virtual NIC"]]/address[@addrtype="ipv4"]/@addr')
['192.168.2.93', '192.168.2.96', '192.168.2.103']
3

如果你必须使用ElementTree(而不是lxml)

>>> [i.get('addr') for i in tree.findall(
...     './host/address[@vendor="QEMU Virtual NIC"]/../address[@addrtype="ipv4"]')]
['192.168.2.93', '192.168.2.96', '192.168.2.103']

lxml是一个更好的库,但如果不允许使用外部依赖,那就只能这样了。

撰写回答