Pep*_*zza 1 python xml beautifulsoup
我有一个 50MB 的 xml 文件,我需要从中读取一些数据。我的方法是使用 Beautifulsoup 4,因为我已经使用该软件包一段时间了。这段代码显示了我是如何做到的:
from bs4 import Beautifulsoup
# since the file is big, this line takes minutes to execute
soup = Beautifulsoup(open('myfile.xml'), 'xml')
items = soup.find_all('item')
for item in items:
name = item['name']
status = item.find('status').text
description = item.find('desc').text
refs = item.findAll('ref')
data = []
for ref in refs:
if 'url' in ref.attrs:
data.append('%s:%s' % (ref['source'], ref['url']))
else:
data.append('%s:%s' % (ref['source'], ref.text))
do_something(data)
Run Code Online (Sandbox Code Playgroud)
该文件不是复杂的 xml,我只需要读取每个<item>条目的每个数据:
<item type="CVE" name="some-name" seq="1999-0003">
<status>Entry</status>
<desc>A description goes here.</desc>
<refs>
<ref source="NAI">NAI-29</ref>
<ref source="CERT">CA-98.11.tooltalk</ref>
<ref source="SGI" url="example.com">Some data</ref>
<ref source="XF">aix-ttdbserver</ref>
<ref source="XF">tooltalk</ref>
</refs>
</item>
Run Code Online (Sandbox Code Playgroud)
我正在使用的这个文件更有可能继续增长,因此最好按块读取它或不加载整个文件。我需要帮助解决这个问题。也许 BS4 以外的其他一些包更快,是否有其他包或避免将整个文件加载到内存中的方法?
您想在这里切换到xml.etree.ElementTree()API;它有一个iterparse()迭代解析功能:
for event, elem in iterparse(source):
if elem.tag == "record":
# do something with the <record> element
elem.clear() # clean up
Run Code Online (Sandbox Code Playgroud)
由于您已经在使用 BeautifulSoup XML 模式,因此您必须已经lxml安装。lxml实现相同的 API,但在 C 中。请参阅lxml iterparse()文档。
请阅读为什么 lxml.etree.iterparse() 占用了我所有的内存?确保在使用时正确清除元素lxml。
默认是只发出end事件;整个标签已被解析,包括子节点。您可以将其用于您的<item>元素:
for event, elem in iterparse(source):
if elem.tag == "item":
status = elem.find('status').text
desc = elem.find('desc').text
refs = {r.get('source'): r.text for r in elem.findall('./refs/ref')}
elem.clear()
Run Code Online (Sandbox Code Playgroud)