Разбор отчета nmap xml с помощью python

Я пытаюсь извлечь некоторые элементы из следующего файла XML (урезанный вывод nmap):

<?xml version="1.0"?>
<nmaprun>
<host starttime="1381245200" endtime="1381245316">
    <address addr="192.168.1.5" addrtype="ipv4"/>
    <hostnames>
      <hostname name="host1.example.com" type="PTR"/>
    </hostnames>
    <os>
        <osmatch>
        <osclass type="general purpose" vendor="Linux" osfamily="Linux" osgen="2.6.X" accuracy="100">
          <cpe>cpe:/o:linux:linux_kernel:2.6</cpe>
        </osclass>
      </osmatch>
    </os>
  </host>
</nmaprun>

со следующим кодом:

import xml.etree.ElementTree as ET

d = [
        {'path': 'address', 'el': 'addr'},
        {'path': 'hostnames/hostname', 'el': 'name'},
        {'path': 'os/osmatch/osclass', 'el': 'osfamily'}
]

tree = ET.parse('testnmap.xml')
root = tree.getroot()
for i in root.iter('host'):
        for h in d:
                if i.find(h['path']): print i.find(h['path']).get(h['el'])
                else: print "UNKNOWN ", (h['path'])

Идея состоит в том, чтобы извлечь IP, имя хоста и ОС. Результат дает мне

UNKNOWN  address
UNKNOWN  hostnames/hostname
Linux

Таким образом, самый внутренний путь работал (osfamily), а другие (имя хоста) не работали. Каким должен быть правильный звонок, чтобы связаться с ними?


person Adz    schedule 10.10.2013    source источник
comment
В качестве альтернативы рассмотрите возможность использования синтаксического анализатора, включенного в скрипт Ndiff Python, который распространяется вместе с Nmap. Он специально разработан для анализа Nmap XML и возврата результатов в объектах Python.   -  person bonsaiviking    schedule 10.10.2013


Ответы (1)


Я думаю, проблема в логическом сравнении i.find(h['path']). Он проверяет, есть ли у этого элемента дочерние элементы, и это происходит только в <osclass>. Вы должны проверить, является ли оно нулевым по сравнению с None, например:

...
e = i.find(h['path'])
if e is not None: print(e.get(h['el']))
...

Это дает:

192.168.1.5
host1.example.com
Linux
person Birei    schedule 10.10.2013
comment
Я не уверен, что понимаю: в чем разница между вызовами i.find("os/osmatch/osclass") и i.find("hostnames/hostname"), .get() впоследствии достигает элементов внутри тега в обоих случаях (я имею в виду, что они получают значение aaa из <tag aaa="bbb">). Ваш код работает и решает проблему - просто я понимаю, почему он работает :) - person WoJ; 10.10.2013
comment
@Woj: Насколько я понимаю, когда элемент существует, но не имеет дочерних элементов, он возвращает False, а когда элемент не существует, возвращает None. В логическом контексте оба значения интерпретируются как False, поэтому требуется явная проверка с None для фильтрации тех элементов, которые не могут быть найдены. Итак, <hostname> был UNKNOWN, потому что у него нет детей, но у <osclass> был один, <cpe>. - person Birei; 10.10.2013
comment
теперь все ясно - я не осознавал, что в зависимости от существования дочерних элементов возвращались два разных значения, оба False для if. Благодарю за разъяснение! - person WoJ; 10.10.2013