Я пытаюсь проанализировать файл dblp.xml (3,2 ГБ), используя lxml. Ниже приведен мой код.

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 уже находятся в корневой папке.

Пожалуйста помоги!

0
Jas 19 Янв 2022 в 12:21
Путь к dblp.xml правильный? Возможно, вы захотите использовать полный путь, чтобы быть уверенным.
 – 
Maurice Meyer
19 Янв 2022 в 12:24
Попробуйте etree.parse('/dblp.xml'), так как он находится в корневом каталоге
 – 
JCaesar
19 Янв 2022 в 12:27
OSError указывает, что dblp.xml отсутствует в текущем рабочем каталоге IPython. Если вы отсортируете это, вполне вероятно, что вы столкнетесь с проблемами памяти, так как файл очень большой.
 – 
mzjn
20 Янв 2022 в 14:55

2 ответа

Вы можете использовать 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

Это позволит вам извлекать только те объекты, которые вам нужны, игнорируя другие.

1
Jan Jaap Meijerink 19 Янв 2022 в 12:25

Как заявил Ян Яап Мейеринк, вы можете попробовать использовать 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

В конце концов, если вы предпочитаете попробовать использовать синтаксический анализ, вы можете определить синтаксический анализатор xml с включенным huge_tree и установить его по умолчанию для дальнейшего использования 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)

После этих операторов вы можете использовать etree.parser с настроенным XMLPARSER. Однако остерегайтесь многопоточности (https://lxml.de/1.3/ api/lxml.etree-module.html#set_default_parser).

Добавление ключевого слова resolve_entities, remove_pis и no_network может (по крайней мере, немного) снизить риск парсинга огромных внешних файлов, если они исходят из ненадежного источника.

0
Maciej Wrobel 20 Янв 2022 в 14:17