Вопрос по python, linux, ms-word – извлечение текста из файлов MS Word в Python

27

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

Можете ли вы определить "работать с"? Только чтение или тоже письмо? Mawg

Ваш Ответ

14   ответов
3
2

что такой вещи не существует. Есть только отвеченные и неотвеченные. Этот довольно без ответа, или наполовину ответили, если хотите. Что ж, способы чтения документов * .docx (MS Word 2007 и более поздних версий) без использования COM-взаимодействия рассматриваются. Но методы извлечения текста из * .doc (MS Word 97-2000), использующие только Python, отсутствуют. Это сложно? Чтобы сделать: не совсем, чтобы понять: хорошо, что 'Это другая вещь.

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

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

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

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


doc2text module:
"""
This is Python implementation of C# algorithm proposed in:
http://b2xtranslator.sourceforge.net/howtos/How_to_retrieve_text_from_a_binary_doc_file.pdf

Python implementation author is Dalen Bernaca.
Code needs refining and probably bug fixing!
As I am not a C# expert I would like some code rechecks by one.
Parts of which I am uncertain are:
    * Did the author of original algorithm used uint32 and int32 when unpacking correctly?
      I copied each occurence as in original algo.
    * Is the FIB length for MS Word 97 1472 bytes as in MS Word 2000, and would it make any difference if it is not?
    * Did I interpret each C# command correctly?
      I think I did!
"""

from compoundfiles import CompoundFileReader, CompoundFileError
from struct import unpack

__all__ = ["doc2text"]

def doc2text (path):
    text = u""
    cr = CompoundFileReader(path)
    # Load WordDocument stream:
    try:
        f = cr.open("WordDocument")
        doc = f.read()
        f.close()
    except: cr.close(); raise CompoundFileError, "The file is corrupted or it is not a Word document at all."
    # Extract file information block and piece table stream informations from it:
    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]
    # Load piece table stream:
    try:
        f = cr.open(tableName)
        table = f.read()
        f.close()
    except: cr.close(); raise CompoundFileError, "The file is corrupt. '%s' piece table stream is missing." % tableName
    cr.close()
    # Find piece table inside a table stream:
    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":
            # This is beggining of some other substructure, we skip it:
            pos = pos+1+1+ord(clx[pos+1])
        else: break
    if not pieceTable: raise CompoundFileError, "The file is corrupt. Cannot locate a piece table."
    # Read info from pieceTable, about each piece and extract it from WordDocument stream:
    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())
3
Число рейнольдса Ваши правки стиля и грамматики: я предпочел свой собственный стиль и грамматику, спасибо. Хороший редактор не делаетнавязать свой собственный стиль. И действительно, ни у кого из нас нет достаточно свободного времени, чтобы выполнять обычную проверку орфографии и грамматики, не так ли? Я думаю, что вы можете найти это немного чрезмерно. Я markling
Ах, Филипп! Я просто искал способ отклонить тривиальные изменения стиля, которые вы внесли в другой мой пост. Я пытался связаться с вами напрямую. Пожалуйста, уточните, что вы предлагаете здесь? Этот ответ, который я дал здесь, является ответом на вопрос. Isn»это достаточно хорошо? markling
13

БенжаминОтвет довольно хороший. Я только что консолидировал ...


docx = zipfile.ZipFile('/path/to/file/mydocument.docx')
content = docx.read('word/document.xml').decode('utf-8')
cleaned = re.sub('<(.|\n)*?>','',content)
print(cleaned)
Я должен повторить, что это работает только для DOCX (Word 2007 или более поздней версии). Для файлов .doc wvware - ваш лучший выбор. В зависимости от вашей среды это может быть проблематично при настройке, но это делает очень хорошую работу. Chad
content = docx.read ('слово / document.xml») .Decode (»UTF-8') в противном случае вы получите ошибку при очистке: TypeError: нельзя использовать строковый шаблон для объекта, подобного байту Ashutosh Tripathy
Чтобы удалить объекты XML, такие как &NBSP; от 'текст ': >>>из xml.sax.saxutils импорт unescape >>>Текст = экранирование в (очищенный) Jesvin Jose
4

одпроцесса, вы можете использовать модуль Python zipfile.

content = ""
# Load DocX into zipfile
docx = zipfile.ZipFile('/home/whateverdocument.docx')
# Unpack zipfile
unpacked = docx.infolist()
# Find the /word/document.xml file in the package and assign it to variable
for item in unpacked:
    if item.orig_filename == 'word/document.xml':
        content = docx.read(item.orig_filename)

    else:
        pass

Ваша строка содержимого, однако, должна быть очищена, один из способов сделать это:

# Clean the content string from xml tags for better search
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

# Assemble a new string with all pure content
content = " ".join(fullyclean)

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

С помощью повторного модуля очистка может быть намного проще:stripped_content = re.compile(b'').sub(b' ', content ) # strip tags Одна вещь, которую я не мог понять в вашем коде, в предыдущем фрагменте почемут тыbreakвыходя внутрьif блок? Vikas Prasad
Чтобы удалить объекты XML, такие как &NBSP; от 'текст ': >>>из xml.sax.saxutils импорт unescape >>>Текст = экранирование в (содержание) Jesvin Jose
4

как работает формат doc а такжесоздать текстовый документ с использованием PHP в Linux, Первое особенно полезно.Abiword мой рекомендуемый инструмент. Естьограничения хоть:

Однако если документ содержит сложные таблицы, текстовые поля, встроенные электронные таблицы и т. Д., Он может работать не так, как ожидалось. Разработка хороших фильтров MS Word - очень сложный процесс, поэтому, пожалуйста, будьте терпеливы, когда мы работаем над тем, чтобы документы Word открывались правильно. Если у вас есть документ Word, который не загружается, откройте ошибку и включите документ, чтобы мы могли улучшить импортер.

Abiword не делаетне предположить, что этодокумент HTML, и учитывая, насколько обширный инструмент ... Я нене думаю, что это былолегко" реализовать это. Abiword - это инструмент, который помогает вам читать файлы MS Word ... и, поскольку автор занимается поиском текста, этого достаточно. Swati
Ах яЯ всегда думал, что abiword был просто еще одним текстовым процессором! Чувак, это избавило бы меня от головной боли. William Keller
Не только это, хотя! Даже самый простой текст, сохраненный в формате Word 97, почти невозможно легко получить, не полагаясь на слово, которое сделает это за вас (COM). Большинство текстовых документов не являются HTML! William Keller
3

что тыбудет много удачи без использования COM. Формат .doc до смешного сложен, и его часто называют "дамп памяти слова во время сохранения!

В Свати этоs в HTML, что хорошо и здорово, но большинство текстовых документов нетак мило!

4

этот вопрос также, но здесь это кажется уместным, поэтому, пожалуйста, извините за репост.)

Теперь, это довольно уродливо и довольно хакерски, но мне кажется, что это работает для базового извлечения текста. Очевидно, что для использования этого в программе Qt вы 'Я должен создать процесс для него и т. д., но командная строка I 'взломан вместе это:

unzip -p file.docx | grep '<w:t' |="" sed="" 's="" <[^<]*="">//g' | grep -v '^[[:space:]]*$'
</w:t'>

Чтобы's:

распаковать -p файл.docx: -p == "распаковать на стандартный вывод "

grep '<ш: т»: Захватить только строки, содержащие '<w: t '(<ш: т> является элементом Word 2007 XML для "текст"насколько я могу судить)

седьс / <[^ <]>//г'*: Удалить все внутри тегов

grep -v '^ [[: Пространство:]] $»*: Убрать пустые строки

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

Насколько я'На мой взгляд, у всех архивов, unzip, grep и sed есть порты для Windows и любого из Unix, поэтому он должен быть достаточно кроссплатформенным. Невзирая на то, чтобы быть немного уродливым хаком;)

30

Использоватьродной модуль Python docx, Вот'Как извлечь весь текст из документа:

document = docx.Document(filename)
docText = '\n\n'.join([
    paragraph.text.encode('utf-8') for paragraph in document.paragraphs
])
print docText

УвидетьСайт Python DocX

Также проверьтеTextract который вытаскивает столы и т. д.

Синтаксический анализ XML с помощью регулярных выражений вызывает cthulu. Дон»не делай этого!

я создал вопрос вstackoverflow.com/questions/48800385/... Joyson
Этот код привел к ошибке для меня: para.text.encode ('UTF-8') для абзаца в document.paragraphs TypeError: элемент последовательности 0: ожидаемый экземпляр str, найдены байты MyopicVisage
ты делаешьfrom docx import * Вот? если нет, то как тыgetdocumenttext, так далее.? dbliss
@MyopicVisage проверить официальный сайт - этоВозможно, последняя версия имеет другую подпись. mikemaccana
5

что это старый вопрос, но недавно я пытался найти способ извлечь текст из файлов 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)

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

Надеюсь, это поможет любому, кто столкнется с подобными проблемами в будущем.

11

посмотреть здесь.

Поскольку OOo может без проблем загружать большинство файлов MS Word, ясказал бы этоВаша лучшая ставка.

Как MS Word N + 1 открывает MS Word N файлов, и лучше, чем MS Word N + 1 открывает MS Word N-1 файлов, IMHO Esteban Küber
Не без нареканий. Близко, но далеко не безупречно в моем опыте (OO 2.0 - 3.0). SpliFF
3

включая файлы .docx, вы можете использоватьпитон-DOCX пакет:

from docx import Document
document = Document('existing-document-file.docx')
document.save('new-file-name.docx')

Чтобы прочитать файлы .doc из Word 2003 и более ранних версий, выполните вызов подпроцесса дляAntiword, Сначала вам нужно установить antiword:

sudo apt-get install antiword

Затем просто вызовите его из скрипта Python:

import os
input_word_file = "input_file.doc"
output_text_file = "output_file.txt"
os.system('antiword %s > %s' % (input_word_file, output_text_file))
20

Antiword, Antiword - это утилита командной строки linux для вывода текста из слова doc. Работает довольно хорошо для простых документов (очевидно, он теряет форматирование). Это'Он доступен через apt и, возможно, как RPM, или вы можете скомпилировать его самостоятельно.

catdoc также работает, если антислово не доступно. Xiflado
antiword может конвертировать текстовые документы в DocBook XML, что сохранит (хотя бы немного) форматирование. Marius Gedminas
1

Miette, Должен работать на любой платформе.

Похожие вопросы