如何遍历使用Python的elementtree模块解析的元素树?

1 投票
1 回答
1913 浏览
提问于 2025-04-18 18:05

我昨天花了大约半天时间在交互式的Python命令行上玩ElementTree,结果搞得我一头雾水。根据这个网站 https://docs.python.org/2/library/xml.etree.elementtree.html#module-xml.etree.ElementTree,我通过以下方式加载了树:

import xml.etree.ElementTree as ET
tree = ET.parse('nmaptest.xml')
root = tree.getroot()

然后我开始看一些例子,试着弄明白如何访问和遍历每个元素。每当我觉得自己开始理解它是怎么构成的时候,结果又无法实现我想要的功能。

最终我想解析这些数据,并把相关信息放进数据库,以便以后比较(或者也许写个脚本来简单比较两个XML文档,但目前这超出了我的能力范围)。

我尝试了一些像下面这样的代码:

for host in root.iter('host'):
    print host.attrib['name']
    for address in host.iter('address'):
            print address.attrib['addr']
            for port in host.iter('port'):
                    print port.attrib['portid']

我想打印出每个主机名、IP地址和开放的端口……但是效果不太好,感觉主机名和地址就像在完全不同的世界里,我也不知道为什么会这样。我还发现可以通过简单地这样做来访问地址:

print host[1].attrib['addr']

但我发现当用整数索引时,比如上面的情况(因为host[3]似乎并不是主机名,虽然从逻辑上讲应该是,而host[2]看起来是主机名,但没有.attrib或其他东西),我找不到任何一致性。有时候我觉得找到了我想要的东西,但看到的却是像这样:

for host in root.iter('host'):
    print host[1].attrib

{'addrtype': 'ipv4', 'addr': '10.1.102.255'}

我在某些东西上调用.attrib时,看到的却是空的括号{},就像我这样做时:

for host in root.iter('host'):
    print host[2].attrib

所以我完全不明白它是如何解析这个文档的……我想知道有没有人能帮我理清思路,或者指引我一些可能有帮助的文档?

这是XML输出中的一个示例条目……

<host starttime="1408488852" endtime="1408499159"><status state="up" reason="user-set" reason_ttl="0"/>
  <address addr="X.X.X.X" addrtype="ipv4"/>
  <hostnames>
      <hostname name="computername.domainname.com" type="PTR"/>
  </hostnames>
  <ports>
    <extraports state="filtered" count="986">
      <extrareasons reason="no-responses" count="986"/>
    </extraports>
    <port protocol="tcp" portid="X"><state state="open" reason="syn-ack" reason_ttl="127"/>    <service name="X" method="table" conf="3"/></port>
    <port protocol="tcp" portid="X"><state state="open" reason="syn-ack" reason_ttl="127"/>    <service name="X" method="table" conf="3"/></port>
    <port protocol="tcp" portid="X"><state state="open" reason="syn-ack" reason_ttl="127"/>    <service name="X" method="table" conf="3"/></port>
  </ports>
  <times srtt="332" rttvar="164" to="100000"/>
</host>    

1 个回答

1

这段代码中,

for host in root.iter('host'):
    print host.attrib['name']

你试图访问host元素的name属性。但实际上,hostname元素才有这个属性。

这里有一种方法可以获取你想提取的数据(假设在nmaptest.xml文件中,有一个或多个host元素作为共同根元素的子元素):

import xml.etree.ElementTree as ET
tree = ET.parse('nmaptest.xml')

hosts = tree.findall(".//host")

for host in hosts:
    for elem in host.iter():
        if elem.tag == "hostname":
            print elem.attrib['name']
        if elem.tag == "address":
            print elem.attrib['addr']
        if elem.tag == "port":
            print elem.attrib['portid']

输出结果:

X.X.X.X
computername.domainname.com
X
X
X

撰写回答