XML 到 CSV Python 3.5.2
XML To CSV Python 3.5.2
我正在尝试将以下 XML 转换为 CSV。问题是每个条目可能都没有值,所以它 returns 一个 NoneType
。例如,在下面显示的 XML 中,并非每个 "entry" 都会有一个 "rule"。
如果发生这种情况,我希望 CSV 文件不包含任何内容或包含通用值,例如 "EMPTY"。我希望 CSV 文件看起来像这样:
domain serial seqno rule
1 43434343434 1 21
1 43434343434 1 21
1 43434343434 1 EMPTY
通过使用下面显示的列表理解,我能够避免 NoneType
错误。但是,似乎我需要一些帮助来格式化 CSV 中的数据。
rows = [cleanhtml(str(entry))
for entry in soup.find_all("entry")
if entry.find(header_list[counter]) is not None]
#!/usr/bin/env python3
import csv
import re
from bs4 import BeautifulSoup
html_results='''<response status="success"><result>
<job>
<tenq>09:48:24</tenq>
<tdeq>09:48:24</tdeq>
<tlast>18:00:00</tlast>
<status>FIN</status>
<id>5955</id>
<cached-logs>1118</cached-logs>
</job>
<log>
<logs count="100" progress="100">
<entry logid="4343">
<domain>1</domain>
<serial>43434343434</serial>
<seqno>0</seqno>
<actionflags>0x0</actionflags>
<type>EXAMPLE</type>
<subtype>EXAMPLE</subtype>
<config_ver>0</config_ver>
<src>1.1.1.1</src>
<dst>1.1.1.1</dst>
<rule>Rule 21</rule>
</entry>
<log>
<entry logid="4343">
<domain>1</domain>
<serial>43434343434</serial>
<seqno>0</seqno>
<actionflags>0x0</actionflags>
<type>EXAMPLE</type>
<subtype>EXAMPLE</subtype>
<config_ver>0</config_ver>
<src>1.1.1.1</src>
<dst>1.1.1.1</dst>
<rule>Rule 21</rule>
</entry>'''
def cleanhtml(raw_html):
tags = re.compile('<.*?>')
cleantext = re.sub(tags, '', raw_html)
return cleantext
soup = BeautifulSoup(html_results, 'html.parser')
header_list = ['domain',"serial","seqno","actionflags","type","subtype","config_ver","src","dst","rule"]
query_results = open("query_results.csv","w")
csvwriter = csv.writer(query_results)
csvwriter.writerow(header_list)
num_of_logs = soup.find("logs").get("count")
counter = 0
rows = [cleanhtml(str(entry)) for entry in soup.find_all("entry") if entry.find(header_list[counter]) is not None]
csvwriter.writerows(rows)
query_results.close()
您没有处理您的条目子元素;您只是将每个条目转换为文本并删除 XML 标签标记。您需要生成一个列表或字典,其中每个子元素条目都单独梳理出来。
如果您生成嵌套元素的 字典 ,则 csv.DictWriter()
class 可以为您填充空列,无需额外编码:
def entry_to_dict(entry):
return {tag.name: tag.get_text() for tag in entry.find_all()}
header_list = ['domain', 'serial', 'seqno', 'actionflags', 'type', 'subtype', 'config_ver', 'src', 'dst', 'rule']
soup = BeautifulSoup(html_results, 'html.parser')
with open("query_results.csv","w") as query_results:
csvwriter = csv.DictWriter(query_results, header_list, restval='EMPTY')
csvwriter.writeheader()
csvwriter.writerows(entry_to_dict(entry) for entry in soup.find_all('entry'))
这里,restval
参数告诉作者如何处理每行中的缺失值。 header_list
作为字段名称传入,因此作者知道每行字典中期望的键。
entry_to_dict()
只是将条目中的每个嵌套元素转换为字典中的键值对,而 tag.get_text()
function 负责将元素内容转换为文本。
对于您的演示 XML 数据,这会产生:
>>> import sys
>>> csvwriter = csv.DictWriter(sys.stdout, header_list, restval='EMPTY')
>>> csvwriter.writeheader()
domain,serial,seqno,actionflags,type,subtype,config_ver,src,dst,rule
>>> csvwriter.writerows(entry_to_dict(entry) for entry in soup.find_all('entry'))
1,43434343434,0,0x0,EXAMPLE,EXAMPLE,0,1.1.1.1,1.1.1.1,Rule 21
1,43434343434,0,0x0,EXAMPLE,EXAMPLE,0,1.1.1.1,1.1.1.1,Rule 21
这实际上不包含任何空元素,但是当我添加一些时,您可以看到 EMPTY
用于填充那些:
>>> html_results += '''</log><log>
... <entry logid="4343">
... <domain>1</domain>
... <serial>43434343434</serial>
... <seqno>0</seqno>
... <actionflags>0x0</actionflags>
... <type>EXAMPLE</type>
... <subtype>EXAMPLE</subtype>
... <!-- incomplete entry, config_ver, src, dst and rule missing -->
... </entry>
... </log>'''
>>> soup = BeautifulSoup(html_results, 'html.parser')
>>> csvwriter = csv.DictWriter(sys.stdout, header_list, restval='EMPTY')
>>> csvwriter.writeheader()
domain,serial,seqno,actionflags,type,subtype,config_ver,src,dst,rule
>>> csvwriter.writerows(entry_to_dict(entry) for entry in soup.find_all('entry'))
1,43434343434,0,0x0,EXAMPLE,EXAMPLE,0,1.1.1.1,1.1.1.1,Rule 21
1,43434343434,0,0x0,EXAMPLE,EXAMPLE,0,1.1.1.1,1.1.1.1,Rule 21
1,43434343434,0,0x0,EXAMPLE,EXAMPLE,EMPTY,EMPTY,EMPTY,EMPTY
最后一点:考虑安装 lxml
library,并在 BeautifulSoup:
中使用 xml
解析器
soup = BeautifulSoup(html_results, 'xml')
这确保您的 XML 始终被正确解析(HTML 解析器以 XML 不应该的方式容错,并且不区分大小写,这可能会导致大小写混合 XML 数据出现问题)。
我正在尝试将以下 XML 转换为 CSV。问题是每个条目可能都没有值,所以它 returns 一个 NoneType
。例如,在下面显示的 XML 中,并非每个 "entry" 都会有一个 "rule"。
如果发生这种情况,我希望 CSV 文件不包含任何内容或包含通用值,例如 "EMPTY"。我希望 CSV 文件看起来像这样:
domain serial seqno rule
1 43434343434 1 21
1 43434343434 1 21
1 43434343434 1 EMPTY
通过使用下面显示的列表理解,我能够避免 NoneType
错误。但是,似乎我需要一些帮助来格式化 CSV 中的数据。
rows = [cleanhtml(str(entry))
for entry in soup.find_all("entry")
if entry.find(header_list[counter]) is not None]
#!/usr/bin/env python3
import csv
import re
from bs4 import BeautifulSoup
html_results='''<response status="success"><result>
<job>
<tenq>09:48:24</tenq>
<tdeq>09:48:24</tdeq>
<tlast>18:00:00</tlast>
<status>FIN</status>
<id>5955</id>
<cached-logs>1118</cached-logs>
</job>
<log>
<logs count="100" progress="100">
<entry logid="4343">
<domain>1</domain>
<serial>43434343434</serial>
<seqno>0</seqno>
<actionflags>0x0</actionflags>
<type>EXAMPLE</type>
<subtype>EXAMPLE</subtype>
<config_ver>0</config_ver>
<src>1.1.1.1</src>
<dst>1.1.1.1</dst>
<rule>Rule 21</rule>
</entry>
<log>
<entry logid="4343">
<domain>1</domain>
<serial>43434343434</serial>
<seqno>0</seqno>
<actionflags>0x0</actionflags>
<type>EXAMPLE</type>
<subtype>EXAMPLE</subtype>
<config_ver>0</config_ver>
<src>1.1.1.1</src>
<dst>1.1.1.1</dst>
<rule>Rule 21</rule>
</entry>'''
def cleanhtml(raw_html):
tags = re.compile('<.*?>')
cleantext = re.sub(tags, '', raw_html)
return cleantext
soup = BeautifulSoup(html_results, 'html.parser')
header_list = ['domain',"serial","seqno","actionflags","type","subtype","config_ver","src","dst","rule"]
query_results = open("query_results.csv","w")
csvwriter = csv.writer(query_results)
csvwriter.writerow(header_list)
num_of_logs = soup.find("logs").get("count")
counter = 0
rows = [cleanhtml(str(entry)) for entry in soup.find_all("entry") if entry.find(header_list[counter]) is not None]
csvwriter.writerows(rows)
query_results.close()
您没有处理您的条目子元素;您只是将每个条目转换为文本并删除 XML 标签标记。您需要生成一个列表或字典,其中每个子元素条目都单独梳理出来。
如果您生成嵌套元素的 字典 ,则 csv.DictWriter()
class 可以为您填充空列,无需额外编码:
def entry_to_dict(entry):
return {tag.name: tag.get_text() for tag in entry.find_all()}
header_list = ['domain', 'serial', 'seqno', 'actionflags', 'type', 'subtype', 'config_ver', 'src', 'dst', 'rule']
soup = BeautifulSoup(html_results, 'html.parser')
with open("query_results.csv","w") as query_results:
csvwriter = csv.DictWriter(query_results, header_list, restval='EMPTY')
csvwriter.writeheader()
csvwriter.writerows(entry_to_dict(entry) for entry in soup.find_all('entry'))
这里,restval
参数告诉作者如何处理每行中的缺失值。 header_list
作为字段名称传入,因此作者知道每行字典中期望的键。
entry_to_dict()
只是将条目中的每个嵌套元素转换为字典中的键值对,而 tag.get_text()
function 负责将元素内容转换为文本。
对于您的演示 XML 数据,这会产生:
>>> import sys
>>> csvwriter = csv.DictWriter(sys.stdout, header_list, restval='EMPTY')
>>> csvwriter.writeheader()
domain,serial,seqno,actionflags,type,subtype,config_ver,src,dst,rule
>>> csvwriter.writerows(entry_to_dict(entry) for entry in soup.find_all('entry'))
1,43434343434,0,0x0,EXAMPLE,EXAMPLE,0,1.1.1.1,1.1.1.1,Rule 21
1,43434343434,0,0x0,EXAMPLE,EXAMPLE,0,1.1.1.1,1.1.1.1,Rule 21
这实际上不包含任何空元素,但是当我添加一些时,您可以看到 EMPTY
用于填充那些:
>>> html_results += '''</log><log>
... <entry logid="4343">
... <domain>1</domain>
... <serial>43434343434</serial>
... <seqno>0</seqno>
... <actionflags>0x0</actionflags>
... <type>EXAMPLE</type>
... <subtype>EXAMPLE</subtype>
... <!-- incomplete entry, config_ver, src, dst and rule missing -->
... </entry>
... </log>'''
>>> soup = BeautifulSoup(html_results, 'html.parser')
>>> csvwriter = csv.DictWriter(sys.stdout, header_list, restval='EMPTY')
>>> csvwriter.writeheader()
domain,serial,seqno,actionflags,type,subtype,config_ver,src,dst,rule
>>> csvwriter.writerows(entry_to_dict(entry) for entry in soup.find_all('entry'))
1,43434343434,0,0x0,EXAMPLE,EXAMPLE,0,1.1.1.1,1.1.1.1,Rule 21
1,43434343434,0,0x0,EXAMPLE,EXAMPLE,0,1.1.1.1,1.1.1.1,Rule 21
1,43434343434,0,0x0,EXAMPLE,EXAMPLE,EMPTY,EMPTY,EMPTY,EMPTY
最后一点:考虑安装 lxml
library,并在 BeautifulSoup:
xml
解析器
soup = BeautifulSoup(html_results, 'xml')
这确保您的 XML 始终被正确解析(HTML 解析器以 XML 不应该的方式容错,并且不区分大小写,这可能会导致大小写混合 XML 数据出现问题)。