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

27

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

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

Ваш Ответ

14   ответов
2

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

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

Файл MS Word (* .doc) является составным файлом OLE2. Чтобы не беспокоить вас множеством ненужных подробностей, думайте об этом как о файловой системе, хранящейся в файле. На самом деле используется структура FAT, поэтому определение верно. (Хм, может быть, вы можете смонтировать его в Linux ???) Таким образом, вы можете хранить больше файлов в файле, например, картинки и т. Д. То же самое делается в * .docx, используя вместо этого ZIP-архив. В PyPI есть пакеты, которые могут читать файлы OLE. Как (olefile, составные файлы, ...) Я использовал пакет 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
11

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

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

Не без нареканий. Близко, но далеко не безупречно в моем опыте (OO 2.0 - 3.0).
Как MS Word N + 1 открывает MS Word N файлов, и лучше, чем MS Word N + 1 открывает MS Word N-1 файлов, IMHO
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))
4

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

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

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

Так что

unzip -p file.docx: -p == & quot; распаковать в стандартный вывод & quot;

grep '<w:t': Выберите только строки, содержащие & lt; w: t '; (насколько я могу судить, & lt; w: t & gt; является XML-элементом Word 2007 для "текста")

sed 's/<[^<]& gt; // g & apos; *: удалить все внутри тегов

grep -v '^[[:space:]]$ & apos; *: удалить пустые строки

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

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

20

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

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

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

3
Ах, Филипп! Я просто искал способ отклонить тривиальные изменения стиля, которые вы внесли в другой мой пост. Я пытался связаться с вами напрямую. Пожалуйста, уточните, что вы предлагаете здесь? Этот ответ, который я дал здесь, является ответом на вопрос. Разве это не достаточно хорошо?
Число рейнольдса Ваши правки стиля и грамматики: я предпочел свой собственный стиль и грамматику, спасибо. Хороший редактор не навязывает свой собственный стиль. И действительно, ни у кого из нас нет достаточно свободного времени, чтобы выполнять обычную проверку орфографии и грамматики, не так ли? Я думаю, вы можете найти это немного несерьезным.
30

native Python docx module, Вот как можно извлечь весь текст из документа:

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. Не делай этого!

Этот код привел к ошибке для меня: абзац.text.encode ("utf-8") для абзаца в document.paragraphs TypeError: элемент последовательности 0: ожидаемый экземпляр str, найдены байты
ты делаешьfrom docx import * Вот? если нет, то как тыgetdocumenttext, так далее.?
opendocx отсутствует в модуле (возможно, это было в 2009 году). Документы открываются через класс Document, например,import docx; document = docx.Document('Hello world.docx').
@egpbos Я обновил пример кода, чтобы использовать python-docx нового поколения.
@MyopicVisage проверьте официальный сайт - возможно, последняя версия имеет другую подпись.
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 блок?
Чтобы удалить объекты XML, такие как & amp; nbsp; из "текста": & gt; & gt; из xml.sax.saxutils импортировать unescape & gt; text = unescape (содержимое)
4

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

However, if the document has complicated tables, text boxes, embedded spreadsheets, and so forth, then it might not work as expected. Developing good MS Word filters is a very difficult process, so please bear with us as we work on getting Word documents to open correctly. If you have a Word document which fails to load, please open a Bug and include the document so we can improve the importer.

Ах, я всегда думал, что abiword - это просто еще один текстовый процессор! Чувак, это избавило бы меня от головной боли.
Не только это, хотя! Даже самый простой текст, сохраненный в формате Word 97, почти невозможно легко получить, не полагаясь на слово, которое сделает это за вас (COM). Большинство текстовых документов не являются HTML!
Abiword не предполагает, что это HTML-документ, и учитывая, насколько обширный инструмент ... Я не думаю, что это было "легко" реализовать это. Abiword - это инструмент, который помогает вам читать файлы MS Word ... и, поскольку автор занимается поиском текста, этого достаточно.
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)
Чтобы удалить объекты XML, такие как & amp; nbsp; из "текста": & gt; & gt; из xml.sax.saxutils импортировать unescape & gt; text = unescape (очищено)
Я должен повторить, что это работает только для DOCX (Word 2007 или более поздней версии). Для файлов .doc wvware - ваш лучший выбор. В зависимости от вашей среды это может быть проблематично при настройке, но это делает очень хорошую работу.
content = docx.read ("word / document.xml"). decode ("utf-8"), в противном случае вы получите ошибку при очистке: TypeError: не можете использовать строковый шаблон в байтовоподобном объекте
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, готовой к использованию.

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

3

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

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

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