Как получить IP-адрес из вывода nmap в XML с конкретным поставщиком, используя ElementTree в Python

Используя вывод XML из nmap для доступных виртуальных машин, работающих на хост-компьютере, полученный с помощью nmap -oX output.xml -sP 192.168.2.*, я хотел бы получить IP-адрес каждой машины, поставщик которой соответствует QEMU Virtual NIC. Я решил использовать Python ElementTree XML API для этого, но у меня возникли проблемы с изоляцией элементов host с указанными элементами address.

Вот фрагмент вывода 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, я смог найти элементы address с атрибутом требуемого поставщика:

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

Но что мне действительно нужно, так это элементы host, которым принадлежат найденные выше элементы address, чтобы затем я мог найти другие подэлементы address введите «ipv4» для того же хоста, чтобы наконец получить IP-адрес хоста. Может ли кто-нибудь указать мне правильное направление для достижения этого с помощью XPath и ElementTree?


person Claudio    schedule 10.03.2014    source источник


Ответы (2)


Если вы должны использовать 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 - гораздо лучшая библиотека, но если внешние зависимости не разрешены, это придется сделать.

person metatoaster    schedule 10.03.2014
comment
Сработало отлично.. спасибо! Теперь я попытаюсь полностью понять синтаксис... это моя первая попытка. - person Claudio; 11.03.2014
comment
findall может обрабатывать только небольшое подмножество xpath. Это работает, используя то, с чего вы начали, затем используйте .. для резервного копирования на один уровень, затем вернитесь к конкретному узлу с определенным атрибутом addrtype="ipv4". - person metatoaster; 11.03.2014

Хозяева:

./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']
person MattH    schedule 10.03.2014
comment
Спасибо за советы, но я не смог заставить его работать с ElementTree (я получаю SyntaxError: invalid predicate, выполняя findall с этими аргументами. Я постараюсь извлечь уроки из этих примеров, чтобы привыкнуть к этому синтаксису XPath. - person Claudio; 11.03.2014
comment
Обратите внимание, что findall обрабатывает только подмножество полного синтаксиса xpath, а полный синтаксис xpath поддерживается lxml.xpath, а не ElementTree.findall. - person metatoaster; 11.03.2014