Для работы с файлами 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())

Python