Как разобрать огромный XML-файл (на ходу) с помощью Python

У меня есть огромный XML-файл (текущий дамп Википедии). Этот xml, имеющий размер около 45 ГБ, представляет все данные текущей википедии. Первые несколько строк файла (вывод больше):

    <mediawiki xmlns="http://www.mediawiki.org/xml/export-0.8/" xmlns:xsi="http://ww
    w.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mediawiki.org/x
    ml/export-0.8/ http://www.mediawiki.org/xml/export-0.8.xsd" version="0.8" xml:la
    ng="en">
      <siteinfo>
        <sitename>Wikipedia</sitename>
        <base>http://en.wikipedia.org/wiki/Main_Page</base>
        <generator>MediaWiki 1.21wmf6</generator>
        <case>first-letter</case>
        <namespaces>
          <namespace key="-2" case="first-letter">Media</namespace>
          <namespace key="-1" case="first-letter">Special</namespace>
          <namespace key="0" case="first-letter" />
          <namespace key="1" case="first-letter">Talk</namespace>
          <namespace key="2" case="first-letter">User</namespace>
          <namespace key="3" case="first-letter">User talk</namespace>
          <namespace key="4" case="first-letter">Wikipedia</namespace>
          <namespace key="5" case="first-letter">Wikipedia talk</namespace>
          <namespace key="6" case="first-letter">File</namespace>
          <namespace key="7" case="first-letter">File talk</namespace>
          <namespace key="8" case="first-letter">MediaWiki</namespace>
          <namespace key="9" case="first-letter">MediaWiki talk</namespace>
          <namespace key="10" case="first-letter">Template</namespace>
          <namespace key="11" case="first-letter">Template talk</namespace>
          <namespace key="12" case="first-letter">Help</namespace>
          <namespace key="13" case="first-letter">Help talk</namespace>
          <namespace key="14" case="first-letter">Category</namespace>
          <namespace key="15" case="first-letter">Category talk</namespace>
          <namespace key="100" case="first-letter">Portal</namespace>
          <namespace key="101" case="first-letter">Portal talk</namespace>
          <namespace key="108" case="first-letter">Book</namespace>
          <namespace key="109" case="first-letter">Book talk</namespace>
          <namespace key="446" case="first-letter">Education Program</namespace>
          <namespace key="447" case="first-letter">Education Program talk</namespace
    >
          <namespace key="710" case="first-letter">TimedText</namespace>
          <namespace key="711" case="first-letter">TimedText talk</namespace>
        </namespaces>
      </siteinfo>
      <page>
        <title>AccessibleComputing</title>
        <ns>0</ns>
        <id>10</id>
        <redirect title="Computer accessibility" />
        <revision>
          <id>381202555</id>
          <parentid>381200179</parentid>
          <timestamp>2010-08-26T22:38:36Z</timestamp>
          <contributor>
            <username>OlEnglish</username>
            <id>7181920</id>
          </contributor>
          <minor />
          <comment>[[Help:Reverting|Reverted]] edits by [[Special:Contributions/76.2
    8.186.133|76.28.186.133]] ([[User talk:76.28.186.133|talk]]) to last version by 
    Gurch</comment>
          <text xml:space="preserve">#REDIRECT [[Computer accessibility]] {{R from C
    amelCase}}</text>
          <sha1>lo15ponaybcg2sf49sstw9gdjmdetnk</sha1>
          <model>wikitext</model>

...и так далее

Обратите внимание на элемент страницы в дереве. Это соответствует уникальной странице в Википедии. Данный XML состоит из всех страниц Википедии в виде элементов страницы. Мне нужно написать синтаксический анализатор, в котором мне нужно извлечь значение записи заголовка со страницы для всех страниц википедии и предположить (для простоты) распечатать их.

Я пытаюсь построить то же самое с помощью Python (хотя я открыт для переключения на язык, если это предлагает решение). Единственный способ, которым я знаю, это использовать ElementTree.

Однако использование функции parse('file.xml') требует, чтобы сначала был полностью проанализирован весь документ, а затем будут выведены любые результаты. Как видно, я знаю, что весь xml состоит из элементов страницы. Я хочу, чтобы программа начала печатать заголовки, пока она анализирует остальную часть XML. Это даже возможно. Если так, то как?

РЕДАКТИРОВАТЬ Примечание: я привожу пример извлечения заголовков, чтобы упростить вопрос. Тем не менее, мне нужны функции парсинга xml, так как мне нужно извлечь их в будущем.

3 ответа

Решение

Вам нужна библиотека XML на основе событий, которая отправляет вам фрагменты по мере их разбора, а не создает дерево для всего документа. Типичный ответ - модуль xml.sax stdlib, хотя я уверен, что есть много других.

Я не пытался использовать такой большой набор данных, но я обнаружил, что модуль lxml является быстрым и полезным.

Учебник lxml.etree здесь предоставляет пример, который может быть поучительным.

Ключевой параграф:

Очень важным вариантом использования iterparse() является анализ больших сгенерированных файлов XML, например дампов базы данных. Чаще всего эти форматы XML имеют только один основной элемент элемента данных, который висит непосредственно под корневым узлом и повторяется тысячи раз. В этом случае лучше всего разрешить lxml.etree выполнять построение дерева и точно перехватывать только этот один элемент, используя обычный API дерева для извлечения данных.

Конечно, это возможно. Уродливо, вы можете прочитать файл по строкам в текстовом режиме. А затем используйте регулярное выражение или просто простой метод поиска строк (ключевое слово как и) в качестве фильтра, чтобы получить строки в виде

<title>AccessibleComputing</title>

Затем вы можете получить названия и делать то, что вы хотите.

Другие вопросы по тегам