PythonでMicrosoft Word文書を読み取る方法 ― zipfileでdocxのXMLを抽出する
はじめに
失礼を承知で言うと、筆者はMicrosoft Wordも表計算ソフトもそれほど好きではありません。データエンジニアリングの専門家として、テスターの方々からテスト結果をMicrosoft Word形式で受け取ることがよくあります。ため息が出るのも無理はありません。スクリーンショット、リンク、そして長い・非常に長い・極端に長い段落まで、膨大な情報がWordドキュメントに詰め込まれているのです。Microsoft Wordには、本来シンプルなテキストで済むはずの情報を、開くのに時間がかかり、環境によっては書式が崩れてしまうような扱いにくい巨大ファイルへと変えてしまう「特別な才能」があります。
とはいえ、自分にとって不便なものが他人にとっては便利であり、その逆もあるという事実は受け入れるほかありません。
本題に戻りましょう。実は、PythonのWordサポートは決して十分とは言えません。python-docxライブラリではドキュメントの作成や、ファイルサイズ・タイトルといった基本的なメタデータの読み取りは可能ですが、実際の本文コンテンツまでは取得できません。そのため、テスト結果を処理するには独自のコードを用意する必要があります。
今回は、インターネット上で公開されているサンプルWordドキュメントを利用します。ファイルの所在地は次のURLです。
https://file-examples-com.github.io/uploads/2017/02/file-sample_100kB.docx
実装の手順
1. 必要なモジュールをインポートする
まずはインポートから始めましょう。
from zipfile import ZipFile from urllib.request import urlopen from io import BytesIO
2. Wordドキュメントをダウンロードして解凍する
次に、リモートのWordドキュメントをバイナリファイルオブジェクトとして読み込みます。続いてzipfileライブラリで解凍し、解凍されたファイル――すなわちXML――を読み取ります。もちろん、最後に内容を出力します。
file_url = 'https://file-examples-com.github.io/uploads/2017/02/file-sample_100kB.docx'
# Wordドキュメントを読み込む
wordDocx = urlopen(file_url).read()
wordDocx = BytesIO(wordDocx)
document = ZipFile(wordDocx)
# XMLコンテンツを取得する
xml_content = document.read('word/document.xml')
# XMLコンテンツを出力する
print(xml_content.decode('utf-8'))
このコードを実行すると、次のようなXMLが出力されます(長いため抜粋)。文書の本文がword/document.xmlの中に格納されていることが確認できます。
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<w:document xmlns:o='urn:schemas-microsoft-com:office:office'
xmlns:r='https://schemas.openxmlformats.org/officeDocument/2006/relationships'
xmlns:w='https://schemas.openxmlformats.org/wordprocessingml/2006/main' ...>
<w:body>
<w:p>
<w:pPr><w:pStyle w:val='Title'/></w:pPr>
<w:r><w:t xml:space='preserve'>Lorem ipsum </w:t></w:r>
</w:p>
<!-- この後も段落・見出し・箇条書き・ハイパーリンク・図表・表などが続きます -->
</w:body>
</w:document>
仕組みのポイント
- .docxの正体はZIPアーカイブ: Office Open XML形式(.docx)は、複数のXMLファイルをZIPで圧縮したものです。だからこそ、標準ライブラリのzipfileだけで中身にアクセスできます。
- 本文はword/document.xmlに格納される: 文章本体はword/document.xmlに含まれ、スタイル定義はstyles.xml、ヘッダーやフッターはheader*.xml・footer*.xmlなど、役割ごとにファイルが分かれています。
- BytesIOでメモリ上に展開: ダウンロードしたバイト列を一時ファイル化せずにZipFileへ渡せるよう、BytesIOでラップしています。ディスクへの書き込みが不要になるのが利点です。
本文テキストだけを抽出したい場合
生のXMLのままでは読みづらいため、実務ではlxmlやBeautifulSoupなどのXMLパーサーと組み合わせるのがおすすめです。たとえば、全段落からテキスト(w:t要素)を取り出すコードは次のようになります。
from lxml import etree
root = etree.fromstring(xml_content)
ns = {'w': 'https://schemas.openxmlformats.org/wordprocessingml/2006/main'}
for p in root.iter('{https://schemas.openxmlformats.org/wordprocessingml/2006/main}p'):
texts = [t.text for t in p.findall('.//w:t', ns) if t.text]
if texts:
print(''.join(texts))
まとめ
python-docx単体では本文の読み取りに制約がありますが、「docx=ZIP+XML」という構造さえ理解すれば、標準ライブラリだけでドキュメントの中身へ自由にアクセスできます。さらにXMLパーサーを組み合わせれば、段落・見出し・表・ハイパーリンクなども柔軟に抽出でき、テスト結果レポートの自動集計をはじめ、データエンジニアリングの現場での応用範囲は大きく広がります。
-
PythonでWord文書の段落を作成し、画像を挿入する方法
はじめに データエンジニアリングのスペシャリストとして、テスターからMicrosoft Word形式のテスト結果を受け取ることがよくあります。ため息が出るほど…スクリーンショットや非常に長い段落など、大量の情報をWord文書に詰め込んでくるのです。 先日、テストチームから「ツールが生成したテキストと画像(自動スクリーンショットで取得したもの。本記事では扱いません)を文書に挿入するプログラム」の作成を依頼されました。 MS Wordは他のドキュメント形式と異なり、ページという概念を持たず、残念ながら段落ベースで動作します。そのため、改行(ブレーク)やセクションを活用して、文書を適切に分割する必
-
【保存版】Microsoft WordでGrammarlyを無料で使う方法|インストール手順を徹底解説
オフィスワークにおいて、文法スキルは非常に重要です。文法が正確な文章は、読み手にとって理解しやすく、読みやすいコンテンツになります。しかし、作成するすべてのレポートや資料の文法を完璧に保つには時間がかかり、結果的に生産性を低下させる原因にもなりかねません。そんなときに活躍するのが、Grammarlyのような文法チェックツールです。もちろん、Grammarlyは人間の編集者ほど完璧ではありませんが、それにかなり近い精度を誇ります。スペルミス、動詞の一致、主語と述語の整合性、文の構成、句読点の誤りなどを自動でチェックでき、有料版にアップグレードすればさらに高度な機能も利用可能です。文章を書く機会が