Как разделить большие файлы дампа .xml.bz2 из Википедии в Python? - PullRequest
4 голосов
/ 31 мая 2011

Я пытаюсь создать автономный викисловарь, используя файлы дампа Викимедиа (.xml.bz2), используя Python. Я начал с этой статьи в качестве руководства. Он включает в себя несколько языков, я хотел объединить все шаги в один проект Python. Я нашел почти все библиотеки, необходимые для этого процесса. Единственным препятствием на данный момент является эффективное разбиение большого файла .xml.bz2 на несколько файлов меньшего размера для более быстрого анализа во время операций поиска.

Я знаю, что в Python есть библиотека bz2, но она обеспечивает только операции сжатия и распаковки. Но мне нужно что-то, что может сделать что-то вроде bz2recover из командной строки, которое разбивает большие файлы на несколько меньших мусорных блоков.

Еще один важный момент: разделение не должно разбивать содержимое страницы, которое начинается с <page> и заканчивается </page> в сжатом XML-документе.

Есть ли ранее доступная библиотека, которая могла бы справиться с этой ситуацией, или код должен быть написан с нуля? (Любой набросок / псевдокод был бы очень полезен).

Примечание. Я хотел бы сделать полученный пакет кросс-платформенным, поэтому не могу использовать команды, специфичные для ОС.

Ответы [ 3 ]

12 голосов
/ 20 июня 2011

Наконец-то я сам написал скрипт на Python:

import os
import bz2

def split_xml(filename):
    ''' The function gets the filename of wiktionary.xml.bz2 file as  input and creates
    smallers chunks of it in a the diretory chunks
    '''
    # Check and create chunk diretory
    if not os.path.exists("chunks"):
        os.mkdir("chunks")
    # Counters
    pagecount = 0
    filecount = 1
    #open chunkfile in write mode
    chunkname = lambda filecount: os.path.join("chunks","chunk-"+str(filecount)+".xml.bz2")
    chunkfile = bz2.BZ2File(chunkname(filecount), 'w')
    # Read line by line
    bzfile = bz2.BZ2File(filename)
    for line in bzfile:
        chunkfile.write(line)
        # the </page> determines new wiki page
        if '</page>' in line:
            pagecount += 1
        if pagecount > 1999:
            #print chunkname() # For Debugging
            chunkfile.close()
            pagecount = 0 # RESET pagecount
            filecount += 1 # increment filename           
            chunkfile = bz2.BZ2File(chunkname(filecount), 'w')
    try:
        chunkfile.close()
    except:
        print 'Files already close'

if __name__ == '__main__':
    # When the script is self run
    split_xml('wiki-files/tawiktionary-20110518-pages-articles.xml.bz2')
1 голос
/ 31 мая 2011

хорошо, если у вас есть инструмент командной строки, который предлагает функции, которые вам нужны, вы всегда можете заключить его в вызов с помощью подпроцесса модуля

0 голосов
/ 31 мая 2011

Метод, на который вы ссылаетесь, довольно грязный хак:)

Я написал автономный инструмент Wikipedia и просто Sax-разобрал дамп полностью. Пропускная способность полезна, если вы просто направите несжатый xml в stdin с правильного декомпрессора bzip2. Особенно, если это только Викисловарь.

В качестве простого способа тестирования я просто сжал каждую страницу, записал ее в один большой файл и сохранил смещение и длину в cdb (маленькое хранилище значений ключей). Это может быть правильным решением для вас.

Имейте в виду, разметка mediawiki - самый ужасный кусок дерьма, с которым я сталкивался за долгое время. Но в случае с Викисловарём мне, возможно, удастся справиться.

...