web-dev-qa-db-ja.com

MS Wordファイルからテキストを抽出するpython

pythonでMS Wordファイルを操作するために、Windowsで使用できるpython win32拡張機能があります。Linuxで同じようにするにはどうすればよいですか?ライブラリはありますか?

27
Badri

antiword をサブプロセスで呼び出すことができます。 Antiwordは、Word文書からテキストをダンプするためのLinuxコマンドラインユーティリティです。単純なドキュメントではかなりうまく機能します(明らかに、フォーマットが失われます)。 aptを介して、おそらくRPMとして入手できますが、自分でコンパイルすることもできます。

20
John Fouhy

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が呼び出されます。やめろ!

31
mikemaccana

benjamin の答えはかなり良いものです。統合しました...

import zipfile, re

docx = zipfile.ZipFile('/path/to/file/mydocument.docx')
content = docx.read('Word/document.xml').decode('utf-8')
cleaned = re.sub('<(.|\n)*?>','',content)
print(cleaned)
14
Chad

OpenOffice.orgはPythonでスクリプト化できます: ここを参照

OOoはほとんどのMS Wordファイルを問題なくロードできるので、それが最善の策だと思います。

11
Dan Lenski

私はこれが古い質問であることを知っていますが、最近、MS Wordファイルからテキストを抽出する方法を見つけようとしていました。

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.getouput関数を使用して、wvText(Word文書からテキストを抽出し、catでファイル出力を読み取る)のシェルスクリプトをいくつか実行しています。その後、Word文書のテキスト全体が変数outに入れられ、使用できるようになります。

うまくいけば、これが将来同様の問題を抱えている人を助けるでしょう。

5
David

doc形式のしくみPHP)を使用してWord文書を作成する を見てください。前者は特に便利です Abiword は私の推奨ツールです 制限 があります:

ただし、ドキュメントに複雑なテーブル、テキストボックス、埋め込みスプレッドシートなどがある場合、期待どおりに機能しない可能性があります。優れたMS Wordフィルターの開発は非常に難しいプロセスです。Word文書を正しく開く作業に取り組んでいるため、ご容赦ください。ロードに失敗したWord文書がある場合は、バグを開いてその文書を含めてください。これにより、インポーターを改善できます。

4
Swati

サブプロセスを呼び出さずに純粋にpythonモジュールを使用することを意図している場合は、zipfile python modudeを使用できます。

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

ただし、コンテンツ文字列をクリーンアップする必要があります。これを行う1つの方法は次のとおりです。

# 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モジュールを使用して、文字列をクリーンアップするよりエレガントな方法が確かにあります。お役に立てれば。

4
benjamin

(注:私はこれを この質問 にも投稿しましたが、ここでは関連があるようですので、再投稿はご遠慮ください。)

さて、これはかなり醜くてハックですが、基本的なテキスト抽出では私にはうまくいくようです。明らかにこれをQtプログラムで使用するには、そのためにプロセスを生成する必要がありますが、私が一緒にハッキングしたコマンドラインは次のとおりです。

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

だから〜だ:

unzip -p file.docx:-p == "unzip to stdout"

grep '<w:t': '<w:t'(<w:t>は、 「テキスト」、私が知る限り)

sed 's/<[^ <]> // g' *:タグ内のすべてを削除します

grep -v '^ [[:space:]]$' *:空白行を削除

これを行うにはより効率的な方法がおそらくありますが、私がテストしたいくつかのドキュメントで私にはうまくいくようです。

私の知る限り、unzip、grep、およびsedにはすべてWindowsと任意のUnix用のポートがあるため、合理的にクロスプラットフォームである必要があります。卑劣なハックのビットであるDespit;)

4
Ben Williams

LibreOfficeがインストールされている場合、 コマンドラインから呼び出して、ファイルをテキストに変換できます 、次にテキストをPythonにロードします。

3
markling

COMを使わなくても運がいいかどうかはわかりません。 .doc形式は途方もなく複雑であり、保存時にWordの「メモリダンプ」と呼ばれることがよくあります。

Swatiの場合、それはHTMLに含まれています。これは問題がなく、見栄えがしますが、ほとんどのWord文書はそれほど良くありません。

3
William Keller

Unoconvも良い選択肢かもしれません: http://linux.die.net/man/1/unoconv

3
fccoelho

.docxファイルを含むWord 2007以降のファイルを読み取るには、 python-docx パッケージを使用できます。

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

Word 2003以前から.docファイルを読み取るには、サブプロセスに 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))
3

これは古い質問ですか?そんなものは存在しないと思います。回答済みのものと未回答のものだけがあります。これはかなり答えられていないか、もし望むなら半分答えられています。まあ、COM相互運用機能を使用せずに* .docx(MS Word 2007以降)ドキュメントを読み取る方法はすべてカバーされています。しかし、*。doc(MS Word 97-2000)からテキストを抽出するための方法は、Pythonのみを使用して、不足しています。これは複雑ですか?行うこと:本当に、理解すること:よく、それは別のことです。

完成したコードが見つからなかったとき、私はいくつかのフォーマット仕様を読み、他の言語でいくつかの提案されたアルゴリズムを掘り出しました。

MS Word(* .doc)ファイルはOLE2複合ファイルです。多くの不必要な詳細に煩わされないように、それはファイルに格納されたファイルシステムと考えてください。実際にはFAT構造を使用しているため、定義は保持されます。 (うーん、たぶんLinuxでループマウントできますか???)このようにして、画像などのようにファイル内により多くのファイルを保存できます。代わりに、Zipアーカイブを使用して* .docxで同じことを行います。 PyPIでは、OLEファイルを読み取ることができるパッケージがあります。(olefile、compoundfiles、...)のように、compoundfilesパッケージを使用して* .docファイルを開きます。ただし、MS Word 97-2000では、内部サブファイルはXMLまたはHTMLではなく、バイナリファイルです。これでは不十分なので、各サブファイルには他のサブファイルに関する情報が含まれているため、少なくとも2つを読み取り、それに応じて格納されている情報を解明する必要があります。完全に理解するには、 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())
2
Dalen

COMを使用せずに「doc」ファイルを読み取るためのオプション: miette 。どのプラットフォームでも動作するはずです。

1
alecxe