正在使用lxml分析大型XML文件



我正在尝试使用lxml解析dblp.xml文件(3.2gb(。下面是我的代码。

from lxml import etree
from io import StringIO, BytesIO
tree = etree.parse("dblp.xml")

然而,我收到一个错误:

OSError                                   Traceback (most recent call last)
<ipython-input-5-6a342013a160> in <module>
1 from lxml import etree
2 from io import StringIO, BytesIO
----> 3 tree = etree.parse("dblp.xml")
src/lxml/etree.pyx in lxml.etree.parse()
src/lxml/parser.pxi in lxml.etree._parseDocument()
src/lxml/parser.pxi in lxml.etree._parseDocumentFromURL()
src/lxml/parser.pxi in lxml.etree._parseDocFromFile()
src/lxml/parser.pxi in lxml.etree._BaseParser._parseDocFromFile()
src/lxml/parser.pxi in lxml.etree._ParserContext._handleParseResultDoc()
src/lxml/parser.pxi in lxml.etree._handleParseResult()
src/lxml/parser.pxi in lxml.etree._raiseParseError()
OSError: Error reading file 'dblp.xml': failed to load external entity "dblp.xml"

dblp.xml和dblp.dtd都已在根文件夹中。

请帮忙!

您可以使用etree.iterparse来避免在内存中加载整个文件:

events = ("start", "end")
with open("dblp.xml", "r") as fo:
context = etree.iterparse(fo, events=events)
for action, elem in context:
# Do something

这将允许您只提取所需的实体,而忽略其他实体。

正如Jan Jaap Meijerink所说,您可以尝试使用iterparse。您可能还可以禁用lxml安全功能,以防止解析巨大的文件(请参阅https://lxml.de/api/lxml.etree.XMLParser-class.html):
with open('', 'r') as fobj:
for event, elem in  etree.iterparse(
fobj,
huge_tree=True,
):
#do something with element or event

最后,如果您喜欢尝试使用parse,您可以定义启用huge_tree的xml解析器,并将其设置为默认值,以便进一步使用etree.parse:

xml_parser_settings = dict(
huge_tree=True, # resolve_entities=False, remove_pis=True, no_network=True
)
XMLPARSER = etree.XMLParser(xml_parser_settings)
etree.set_default_parser(XMLPARSER)

在这些语句之后,您可以使用配置了XMLPARSER的etree.parser。不过要注意多线程(https://lxml.de/1.3/api/lxml.etree-module.html#set_default_parser)。

添加resolve_enties、remove_pis和no_network关键字可以(至少在一定程度上(降低解析来自不可信来源的巨大extarnal文件的风险。

最新更新