Python实现Windows事件日志XML转CSV:数据提取失败排查
问题:Python提取Windows事件XML数据生成CSV为空
编写Python脚本从包含Windows事件及EventID的XML文件中提取指定数据,生成的CSV文件内容为空,数据提取环节执行失败。以下是原代码及XML示例片段:
原代码
from xml.etree import ElementTree as ET import csv tree = ET.parse("SecurityLog-rev2.xml") root = tree.getroot() url = root[0].tag[:-len("Event")] fieldnames = ['EventID'] with open ('event_log.csv', 'w') as csvfile: writecsv = csv.DictWriter(csvfile, fieldnames = fieldnames) writecsv.writeheader() for event in root: system = event.find(url + "System") output = {} fields = ['EventID'] # for tag,att in fields: # output[tag] = system.find(url + tag).attrib[att] if event.find(url + "EventData") != None: for data in event.find(url + "EventData"): name = data.attrib['Name'] output[name] = data.text writecsv.writerow(output)
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>4634</EventID> <Version>0</Version><Level>0</Level><Task>12545</Task><Opcode>0</Opcode><Keywords>0x8020000000000000</Keywords><TimeCreated SystemTime='2011-04-16T15:07:53.890625000Z'/> <EventRecordID>1410962</EventRecordID><Correlation/><Execution ProcessID='452' ThreadID='3900'/><Channel>Security</Channel><Computer>DC01.AFC.com</Computer><Security/></System> <EventData><Data Name='TargetUserSid'>S-1-5-21-2795111079-3225111112-3329435632-1610</Data> <Data Name='TargetUserName'>grant.larson</Data> <Data Name='TargetDomainName'>AFC</Data><Data Name='TargetLogonId'>0x3642df8</Data><Data Name='LogonType'>3</Data></EventData></Event>
错误原因分析
- 未提取EventID:原代码注释了提取EventID的逻辑,导致
output字典中没有EventID字段。而DictWriter指定的fieldnames仅包含EventID,写入时因无对应数据,生成空行。 - 字段不匹配:即使提取了
EventData中的字段,这些字段不在fieldnames列表里,DictWriter默认不会写入未指定的字段,最终CSV只有表头,无数据。
修复后的代码
from xml.etree import ElementTree as ET import csv tree = ET.parse("SecurityLog-rev2.xml") root = tree.getroot() # 获取XML命名空间前缀 namespace = root[0].tag[:-len("Event")] # 扩展fieldnames,包含需要的EventID和EventData字段 fieldnames = ['EventID', 'TargetUserSid', 'TargetUserName', 'TargetDomainName', 'TargetLogonId', 'LogonType'] with open('event_log.csv', 'w', newline='') as csvfile: writecsv = csv.DictWriter(csvfile, fieldnames=fieldnames) writecsv.writeheader() for event in root: output = {} # 提取System下的EventID system = event.find(namespace + "System") if system is not None: event_id_elem = system.find(namespace + "EventID") if event_id_elem is not None: output['EventID'] = event_id_elem.text # 提取EventData中的字段 event_data = event.find(namespace + "EventData") if event_data is not None: for data in event_data: name = data.attrib.get('Name') if name and name in fieldnames: output[name] = data.text # 写入一行数据(确保至少有EventID字段才写入) if output.get('EventID'): writecsv.writerow(output)
修复说明
- 正确提取EventID:从
System元素下找到EventID子元素,通过.text获取其值,加入output字典。 - 扩展fieldnames:将需要的
EventData字段加入fieldnames,确保DictWriter能写入这些列。 - 空值处理:添加对元素是否存在的判断,避免因元素不存在抛出异常;仅当提取到
EventID时才写入行,过滤无效数据。 - 优化文件写入:添加
newline=''参数,避免Windows下CSV出现空行。
内容的提问来源于stack exchange,提问作者PRobles
相关产品推荐
相关产品推荐

