如何用Python的xml.etree解析Windows安全事件XML并提取指定字段
Windows安全事件XML数据解析方案
需求说明
需解析Windows安全事件XML,完成两个核心操作:
- 输出
System和EventData节点下的所有字段列表 - 根据指定字段集合,提取对应键值对并格式化输出
现有代码仅能处理System节点的直接子节点,无法解析EventData下带Name属性的Data节点。
原始XML数据
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event"> <System> <Provider Name="Microsoft-Windows-Security-Auditing" Guid="{54849625-5478-4994-A5BA-3E3B0328C30D}" /> <EventID>4771</EventID> <Version>0</Version> <Level>0</Level> <Task>14339</Task> <Opcode>0</Opcode> <Keywords>0x8010000000000000</Keywords> <TimeCreated SystemTime="2015-08-07T18:10:21.495462300Z" /> <EventRecordID>166708</EventRecordID> <Correlation /> <Execution ProcessID="520" ThreadID="1084" /> <Channel>Security</Channel> <Computer>DC01.contoso.local</Computer> <Security /> </System> <EventData> <Data Name="TargetUserName">dadmin</Data> <Data Name="TargetSid">S-1-5-21-3457937927-2839227994-823803824-1104</Data> <Data Name="ServiceName">krbtgt/CONTOSO.LOCAL</Data> <Data Name="TicketOptions">0x40810010</Data> <Data Name="Status">0x10</Data> <Data Name="PreAuthType">15</Data> <Data Name="IpAddress">::ffff:10.0.0.12</Data> <Data Name="IpPort">49254</Data> <Data Name="CertIssuerName" /> <Data Name="CertSerialNumber" /> <Data Name="CertThumbprint" /> </EventData> </Event>
现有代码
from tkinter.font import names import xml.etree.ElementTree as ET tree = ET.parse('C:/tmp/test.xml') root = tree.getroot() namespace = "{"+root.tag.split('}')[0].strip('{')+"}" for child in root: print(child.tag, child.attrib) print((''.join([child.tag for child in child.iter()])).replace(namespace,"| ")) print(" ") testlist = ["EventID", "Computer"] i = 0 for tag in testlist: for tag in root.iter(namespace+tag): #'EventID' print(testlist[i],":",tag.text) i += 1
期望输出
System: Provider Name | EventID | Version | Level | Task | Opcode | Keywords | TimeCreated | EventRecordID | ProcessID | ThreadID | Channel | Computer EventData: TargetUserName | TargetSid | ServiceName | TicketOptions | Status | PreAuthType | IpAddress | IpPort | CertIssuerName | CertSerialNumber | CertThumbprint EventID : 4771 Status : 0x10 PreAuthType : 15 Computer : DC01.contoso.local TimeCreated : 2015-08-07T18:10:21.495462300Z TargetUserName : dadmin ServiceName : krbtgt/CONTOSO.LOCAL IpAddress : ::ffff:10.0.0.12 IpPort : 49254
解决方案代码
import xml.etree.ElementTree as ET # 加载XML文件 tree = ET.parse('C:/tmp/test.xml') root = tree.getroot() # 提取命名空间并构建命名空间映射 namespace = root.tag.split('}')[0].strip('{') ns_map = {'win': namespace} # 1. 收集System节点的所有字段 system_fields = [] system_node = root.find('win:System', ns_map) for child in system_node: tag_name = child.tag.split('}')[-1] if tag_name == 'Provider': system_fields.append('Provider Name') elif tag_name == 'TimeCreated': system_fields.append('TimeCreated') elif tag_name == 'Execution': system_fields.extend(['ProcessID', 'ThreadID']) elif tag_name not in ['Correlation', 'Security']: # 跳过无实际内容的节点 system_fields.append(tag_name) # 2. 收集EventData节点的所有字段 event_data_fields = [] event_data_node = root.find('win:EventData', ns_map) for data in event_data_node.findall('win:Data', ns_map): event_data_fields.append(data.attrib['Name']) # 3. 输出字段列表 print(f"System: {' | '.join(system_fields)}") print(f"EventData: {' | '.join(event_data_fields)}") print() # 4. 定义需要提取的目标字段 target_fields = [ "EventID", "Status", "PreAuthType", "Computer", "TimeCreated", "TargetUserName", "ServiceName", "IpAddress", "IpPort" ] # 5. 构建所有字段的键值映射字典 field_value_map = {} # 处理System节点的字段 for child in system_node: tag_name = child.tag.split('}')[-1] if tag_name == 'EventID': field_value_map['EventID'] = child.text elif tag_name == 'Computer': field_value_map['Computer'] = child.text elif tag_name == 'TimeCreated': field_value_map['TimeCreated'] = child.attrib['SystemTime'] elif tag_name == 'Execution': field_value_map['ProcessID'] = child.attrib['ProcessID'] field_value_map['ThreadID'] = child.attrib['ThreadID'] # 处理EventData节点的字段 for data in event_data_node.findall('win:Data', ns_map): field_name = data.attrib['Name'] field_value_map[field_name] = data.text or '' # 6. 按指定顺序输出目标字段的键值对 for field in target_fields: print(f"{field} : {field_value_map.get(field, '')}")
代码说明
- 命名空间处理:使用带命名空间的
find/findall方法,避免因XML命名空间导致的标签匹配失败 - System字段收集:特殊处理
Provider、TimeCreated、Execution等节点,提取对应属性或标签名 - EventData字段收集:直接提取
Data节点的Name属性值作为字段名 - 键值映射构建:遍历节点将字段名与对应值存入字典,方便后续快速查询
- 目标字段输出:按指定列表顺序输出键值对,确保格式完全符合要求
内容的提问来源于stack exchange,提问作者Peter Asp
相关产品推荐
相关产品推荐

