Python

Извлечение текста из файлов MS Word в Python

Для работы с файлами MS Word в Python существуют расширения Python Win32, которые можно использовать в Windows. Как мне сделать то же самое в Linux? Есть ли библиотека?

Ответ 1

Вы можете сделать вызов подпроцесса для antiword. Antiword это утилита командной строки Linux для выгрузки текста из документа word. Работает довольно хорошо для простых документов (очевидно, при этом теряется форматирование). Она доступна через apt, и, вероятно, в виде RPM, или вы можете скомпилировать ее самостоятельно.

Ответ 2

Я недавно пытался найти способ извлечения текста из файлов MS Word, и лучшее решение, которое я нашел, это wvLib:

http://wvware.sourceforge.net/

После установки библиотеки использовать ее в Python довольно просто:

import commands

exe = 'wvText ' + word_file + ' ' + output_txt_file

out = commands.getoutput(exe)

exe = 'cat ' + output_txt_file

out = commands.getoutput(exe)

Вот и все. В основном мы используем функцию commands.getoutput для запуска нескольких сценариев оболочки, а именно wvText (который извлекает текст из документа Word, и cat для чтения вывода файла). После этого весь текст из документа Word окажется в переменной out, готовый к использованию. Надеюсь, это поможет всем, у кого возникнут подобные проблемы в будущем.

Ответ 3

Посмотрите, как работает формат doc, и создайте документ Word с помощью PHP в Linux. Первый вариант особенно полезен. Abiword рекомендуемый мною инструмент. Однако здесь есть свои ограничения: «если в документе есть сложные таблицы, текстовые поля, встроенные электронные таблицы и так далее, то он может работать не так, как ожидается. Разработка хороших фильтров для MS Word очень сложный процесс, поэтому, пожалуйста, потерпите, пока мы работаем над тем, чтобы документы Word открывались правильно. Если у вас есть документ Word, который не загружается, пожалуйста, откройте сообщение об ошибке и укажите документ, чтобы мы могли улучшить импортер».

Ответ 4

Если вы намерены использовать исключительно модули Python без вызова подпроцесса, вы можете использовать zip-файл Python module. 

content = ""

# Загрузка DocX  из zipfile

docx = zipfile.ZipFile('/home/whateverdocument.docx')

# Распаковка zipфайла

unpacked = docx.infolist()

# Найдите файл /word/document.xml в пакете и присвойте его переменной

    if item.orig_filename == 'word/document.xml':

        content = docx.read(item.orig_filename)

    else:

        pass

Однако ваша строка содержимого нуждается в очистке. Один из способов сделать это:

# Очистите строку содержимого от xml-тегов для лучшего поиска

fullyclean = []

halfclean = content.split('<')

for item in halfclean:

    if '>' in item:

        bad_good = item.split('>')

        if bad_good[-1] != '':

            fullyclean.append(bad_good[-1])

        else:

            pass

    else:

        pass

# Соберите новую строку со всем чистым содержимым

content = " ".join(fullyclean)

Но наверняка существует более элегантный способ очистки строки, возможно, с помощью модуля «re». Надеюсь, это поможет.

Ответ 5

Методы чтения документов *.docx (MS Word 2007 и более поздних версий) без использования COM interop это множество вариантов. А вот методы извлечения текста из *.doc (MS Word 97-2000), используя только Python, отсутствуют. Сложно ли это?

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

Файл MS Word (*.doc) это составной файл OLE2. Чтобы не утомлять вас множеством ненужных деталей, думайте о нем как о файловой системе, хранящейся в файле. На самом деле он использует структуру FAT.  Таким образом, вы можете хранить больше файлов внутри файла, например, картинки и т. д. То же самое можно сделать в *.docx, используя вместо него ZIP-архив. На PyPI есть пакеты, которые могут читать OLE-файлы. Например: olefile, compoundfiles... Я использовал пакет compoundfiles для открытия файла *.doc. Однако в MS Word 97-2000 внутренние подфайлы представляют собой не XML или HTML, а бинарные файлы. А поскольку этой информации недостаточно, каждый из них содержит информацию о другом файле. Таким образом, приходится читать как минимум два из них и, соответственно, разгадывать сохраненную информацию. Для полного понимания прочитайте PDF-документ, из которого я взял алгоритм.

Код ниже составлен очень поспешно и протестирован на небольшом количестве файлов. Насколько я могу судить, он работает так, как задумано. Иногда в начале и почти всегда в конце текста появляется какой-то нечитабельный текст. Между ними также могут быть странные символы. 

doc2text module:

"""

Это реализация на Python алгоритма, предложенного для C#:

http://b2xtranslator.sourceforge.net/howtos/How_to_retrieve_text_from_a_binary_doc_file.pdf

 Автор реализации на Python — Дален Бернака.

Код нуждается в доработке и, возможно, в исправлении ошибок!

Поскольку я не являюсь экспертом по C#, я бы хотел, чтобы кто-нибудь перепроверил код.

Части, в которых я не уверен, это:

    * Правильно ли автор оригинального алгоритма использовал uint32 и int32 при распаковке?

      Я скопировал каждый случай, как в оригинальном алгоритме.

    * Является ли длина FIB для MS Word 97 1472 байта, как в MS Word 2000, и есть ли разница, или нет?

"""

from compoundfiles import CompoundFileReader, CompoundFileError

from struct import unpack

 

__all__ = ["doc2text"]

 

def doc2text (path):

    text = u""

    cr = CompoundFileReader(path)

    # Загрузка WordDocument потока:

    try:

        f = cr.open("WordDocument")

        doc = f.read()

        f.close()

    except: cr.close(); raise CompoundFileError, "Файл разрушен или не является файлом MS Word."

    # Извлеките из него блок информации о файле и потоковую информацию о таблице фрагментов:

    fib = doc[:1472]

    fcClx  = unpack("L", fib[0x01a2l:0x01a6l])[0]

    lcbClx = unpack("L", fib[0x01a6l:0x01a6+4l])[0]

    tableFlag = unpack("L", fib[0x000al:0x000al+4l])[0] & 0x0200l == 0x0200l

    tableName = ("0Table", "1Table")[tableFlag]

    # Загрузите поток таблиц кусков:

    try:

        f = cr.open(tableName)

        table = f.read()

        f.close()

    except: cr.close(); raise CompoundFileError, "Файл поврежден. '%s' piece table stream отсутствует." % tableName

    cr.close()

    # Найти часть таблицы внутри потока таблиц:

    clx = table[fcClx:fcClx+lcbClx]

    pos = 0

    pieceTable = ""

    lcbPieceTable = 0

    while True:

        if clx[pos]=="\x02":

            # This is piece table, we store it:

            lcbPieceTable = unpack("l", clx[pos+1:pos+5])[0]

            pieceTable = clx[pos+5:pos+5+lcbPieceTable]

            break

        elif clx[pos]=="\x01":

            # Это начало какой-то другой подструктуры, мы ее пропускаем:

            pos = pos+1+1+ord(clx[pos+1])

        else: break

    if not pieceTable: raise CompoundFileError, "Файл поврежден. Не удается найти таблицу деталей."

    # Считываем информацию из pieceTable о каждом фрагменте и извлекаем ее из потока WordDocument:

    pieceCount = (lcbPieceTable-4)/12

    for x in xrange(pieceCount):

        cpStart = unpack("l", pieceTable[x*4:x*4+4])[0]

        cpEnd   = unpack("l", pieceTable[(x+1)*4:(x+1)*4+4])[0]

        ofsetDescriptor = ((pieceCount+1)*4)+(x*8)

        pieceDescriptor = pieceTable[ofsetDescriptor:ofsetDescriptor+8]

        fcValue = unpack("L", pieceDescriptor[2:6])[0]

        isANSII = (fcValue & 0x40000000) == 0x40000000

        fc      = fcValue & 0xbfffffff

        cb = cpEnd-cpStart

        enc = ("utf-16", "cp1252")[isANSII]

        cb = (cb*2, cb)[isANSII]

        text += doc[fc:fc+cb].decode(enc, "ignore")

    return "\n".join(text.splitlines())

Схожие статьи

Библиотека Json Python: как научиться пользоваться ей самостоятельно?
Python

Библиотека Json Python: как научиться пользоваться ей самостоятельно?

Как в Python присвоить значение переменной? Мануал для новичков
Python

Как в Python присвоить значение переменной? Мануал для новичков

Делаем ботнет на Python
Python

Делаем ботнет на Python

Guide: Type Hinting in Python 3.5
Python

Guide: Type Hinting in Python 3.5