MS-Office 「Word」をPythonで操作する「python-docx」ライブラリを解説します。
Wordでできることは、「文章を作成する」こと以外にも、「画像・図・表を挿入する」「ヘッター/フッターを設定する」「スタイルを定義する」など多岐にわたります。そのため、次の目次のようにテーマごとに複数回の連載記事として解説しています。
連載2回目となる今回は、「Wordドキュメントに画像や表を挿入する方法」とセクションの活用事例として「ヘッダーとフッターを設定する」といった内容を解説します。
文章をメインコンテンツとするWordドキュメントですが、画像や表などを効果的に使うことで、訴求力や信ぴょう性を高めることができます。とりわけ論文・解説書など、公式でしっかりとしたドキュメントの場合は、必須コンテンツとなるでしょう。
また、大きな規模のドキュメントの場合は、ページ管理ユニットであるセクションの導入も検討する必要があります。
「python-docx」はこれらすべてのことに対応できます。
この記事を読むことで、次のようなことが「できる・わかる」ようになりますので最後までお付き合いください。
本サイトでの紹介例は一例です。また、関数などの省略可能なオプション引数などについては割愛していますので、詳細や不明点などは必要に応じて公式サイトなどを参照してください。
<公式サイト>https://python-docx.readthedocs.io/en/latest/
それでは、次節より「python-docx」ライブラリの具体的な扱い方について、解説していきます。
1. 画像をドキュメントに挿入する
本節では、ドキュメントに画像を挿入する手順について解説します。
画像は段落(Paragraphオブジェクト)に配置することができます。さらに段落を構成する文章(Runオブジェクト)中にも埋め込むこともできます。
python-docxではWordドキュメント内の画像やグラフは “InlineShape(Picture)“ [Text Layer] であれば扱うことができますが、次の公式ドキュメントの記載にもあるとおり “FloatingShape” [Drawing Layer] はサポートされていません。
Inline(TextLayter)とは、段落や文章の一部に埋め込むという意味で、文字や画像どうしが行の高さや幅、改行などで互いに干渉し合う階層を指します。
一方、Floating(Drawing Layer)とは、段落と画像の配置レイヤが区別され、互いに干渉することなく、自由に画像や図形などを配置できます。
Understanding pictures and other shapes
At the time of writing, python-docx only supports inline pictures. Floating pictures can be added. If you have an active use case, submit a feature request on the issue tracker.
https://python-docx.readthedocs.io/en/latest/user/shapes.html
また、大変残念ですが「python-docx」では、InlineShapeであっても図形・SmartArtの操作には対応していないようです。Floating(Drawing Layer)の対応と合わせて今後のアップデートに期待しましょう。
現状の画像や図形のサポート状況についてまとめました、参考にして下さい。(図1)
補足として、図形やSmartArt[Inline/Floating Shape]を設定・取得する場合は次の2つの方法があります。目的に応じて「python-docx」と使い分けると良いでしょう。
それでは、次項より段落に画像を挿入するクラスやメソッド・プロパティについて解説していきます。
1.1 段落(Paragraphオブジェクト)に画像を挿入する
段落に画像を設定することができます。新たに追加された段落に画像を挿入するだけであれば、Documentオブジェクト配下の add_picture()メソッド を次の書式のようにして使います。
画像ファイルはjpg/pngフォーマット形式に対応、画像のサイズ指定をする 引数:width/height があります(いずれもオプション)。単位は、mm(ミリ)やInche(インチ)などで指定しますが、省略した場合は元のサイズが適用されます。
また、片方のみを指定した場合は、同じアスペクト比で自動調整します。
【SAMPLE(1)】
それでは、サンプルコードによる実例を紹介します。
コードの概要は、add_picture()メソッドにより画像3枚を貼ります。新規段落が追加された上で画像が挿入される点に注目してください。
このコードで使用した画像ファイル(.png)は以下からダウンロードできます。カレントディレクトリ配下にpictureフォルダを作ってその下に置いて実行してください。
from docx import Document
from docx.enum.text import WD_ALIGN_PARAGRAPH # 段落位置の定義クラス
from docx.shared import Mm # 単位や色が定義されているSharedクラス
doc1=Document()
# 段落"1"
p1 = doc1.add_paragraph('画像1(.png)を挿入します。')
# 段落"2" add_pictureメソッドpng画像(幅50mm)を挿入
doc1.add_picture('./picture/picture1.png', width=Mm(50))
# 段落"3"
p3 = doc1.add_paragraph('画像2(.jpeg)を挿入します。')
# 段落"4" add_pictureメソッドjpec画像(幅50mm)を挿入
doc1.add_picture('./picture/picture2.jpg', width=Mm(50))
# 段落"5"
p5 = doc1.add_paragraph('画像3(.png)を挿入します。')
# 段落"6" add_pictureメソッドpng画像(高さ50mm)を挿入
doc1.add_picture('./picture/picture3.png', height=Mm(50))
print(len(doc1.paragraphs)) # >>6 段落の個数を調べる
for p_index in [0, 1, 4, 5]:
# 画像はInlineShapeオブジェクトとして段落として認識され、alignmentプロパティ
# で段落の開始位置を指定することで画像挿入位置を大まかに設定することができる
doc1.paragraphs[p_index].paragraph_format.alignment = WD_ALIGN_PARAGRAPH.CENTER
doc1.save('InsertImage_List1JP.docx')
<List1>の実行結果は以下のようになりました(以下からダウンロードできます)。3つの画像が挿入され、段落の数はadd_picture()メソッドによって追加されたものも含めて6つとなっています。
また段落(Paragraphオブジェクト)の alignmentプロパティ で配置位置を中央合わせになることから、段落の書式が適用されることが確認できます。
1.2 文章の途中に画像を挿入する
文章の任意の場所に画像を挿入することもできます。文章(単語・文字)はRunオブジェクトで管理されていますが、add_picture()メソッド は、Runオブジェクトの配下にも提供されています。書式はParagraphオブジェクト配下のものと全く同じです。
使い方も、段落(Paragraph)に配置する場合と同様です。文章コンテンツと同列にInlineShapeオブジェクトが挿入されます。
【SAMPLE(2)】
ここでも、サンプルコードによる add_picture()メソッド の使用例を紹介します。
使用する画像ファイルは、先の<List1>と同様です、必要に応じてダウングレードして下さい。
from docx import Document
from docx.shared import Mm
doc1=Document()
# 段落 "1"
p1 = doc1.add_paragraph(style='Title')
# add_pictureメソッドで文章の途中に画像を挿入する
p1.add_run().add_picture('./picture/picture1.png', width=Mm(15))
p1.add_run(' Runオブジェクトの ')
p1.add_run().add_picture('./picture/picture2.jpg', width=Mm(15))
p1.add_run(' add_pictureメソッドで画像挿入 ')
p1.add_run().add_picture('./picture/picture3.png', height=Mm(15))
doc1.save('文章中に画像を挿入する.docx')
<List2>の実行結果は以下のようになりました、以下からダウンロードできます。
‘Title’スタイルをもつ段落に対して、Runオブジェクトを追加しながら「文字」と「画像」を交互に挿入しています。
2. 表(テーブル)を挿入する
ドキュメントに表(テーブル)を挿入することができます。
表はpython-docxではTableオブジェクトとして管理されています。TableオブジェクトはDocumentの add_table()メソッド を次の書式で取得します。
表の行数・列数はぞれぞれ、引数:rows/cols に指定します。表全体の色合いやイメージなどのテンプレート(組込みスタイル)は、引数:style に文字列で指定することができます。
組込みスタイルには、以下のようなものが用意されています。(図4)
Tableオブジェクトはさらに列(Column(s)オブジェクト)、行(Row(s)オブジェクト)、セル(Cellオブジェクト)で構成されています。(図5)
Tableオブジェクトは、行・列またはセルを要素とするコレクションであり、Columns/Rowsオブジェクトもまた、セルを要素とするコレクションです。よって、上位のオブジェクトは下位の要素をイテラブルに取得することができます。
Tableオブジェクト配下には関連メソッドやプロパティが多くあります。主要なものは以下があります。
その他、行(Row)・列(Column)・セル(Cell)オブジェクトに関する主なプロパティは以下のようなものがあります。Cellオブジェクトにはこの他にも多くの属性があります。
セルの中に、さらに段落(Paragraphオブジェクト)を追加して、本文と同様にコンテンツを設定できます。(段落については、連載1回目の記事を参照下さい。)
【行・列・セルのオブジェクト各種 】 | 【機能】 | 【その他詳細】 |
---|---|---|
Columnオブジェクト.width | 列の幅を設定する | |
Rowオブジェクト.height | 行の高さを設定する | |
Cellオブジェクト.text | セルに値を設定・取得する | |
Cellオブジェクト.add_paragraphs(text, style) | 段落を追加する | 本文の段落と同様の扱い |
【SAMPLE(3)】
ここで、ドキュメントにテーブル(表)を設置するサンプルコードを紹介します。
コードの概要を説明します。まずは、4行4列のセルを持つテーブルを定義します。その後に、各Cellオブジェクトにアクセスして値や書式を設定していきます。
from docx import Document
from docx.enum.table import WD_ALIGN_VERTICAL # セル内の配置位置の定義
from docx.shared import Mm # 単位系や色の定義
# 列のラベルの定義
col_names = ['氏名', '所属', '給与']
# データ内容の定義
data = [['芥川 龍之介', '総務部', '245000'],
['夏目 漱石', '経理部', '350000'],
['石川 啄木', '営業部', '298000']]
doc1 = Document()
#(A)---------------------------------------------------------------------------------------------------------------
# 1行,3列のTableオブジェクトを取得する
tb1 = doc1.add_table(rows=1, cols=len(col_names), style='Colorful Shading Accent 1')
#(B)---------------------------------------------------------------------------------------------------------------
# 列名を1行目のセルに設定
for i, cell in enumerate(tb1.rows[0].cells): # Cellオブジェクトのコレクションを取得
cell.text = col_names[i] # Cellオブジェクトに値を設定
#(C)---------------------------------------------------------------------------------------------------------------
# 行(Rowオブジェクト)を追加しながら、値を設定
for d in data:
row = tb1.add_row() # Rowオブジェクトの追加
row.height = Mm(8.0) # 行の高さを8mmに指定
for i, cell in enumerate(row.cells): # Cellオブジェクトの取得
cell.text = d[i] # Cellオブジェクトに値を設定
cell.vertical_alignment = WD_ALIGN_VERTICAL.BOTTOM # セル内の配置位置を設定
#(C)---------------------------------------------------------------------------------------------------------------
# 列(Columnオブジェクト)の追加
tb1.add_column(Mm(15.0)) # 幅15㎜の列を追加
print(tb1.columns[3].width.mm) # >>14.993
tb1.cell(0, 3).text = '備考' # 追加列のタイトルを設定
doc1.save('テーブルを挿入する.docx')
それでは、ポイントを解説します。
6,9行目でテーブルのデータセットをリストで用意します。
最後に、add_column()メソッド でColoumnオブジェクトを追加して「備考」ラベルを設置して、4×4のテーブルを完成させます。
<List3>の実行結果は以下のようになりました(以下からダウンロードできます)。
スタイルやサイズや幅・高さなどのディメンジョンが指定したものとなり綺麗なテーブルを挿入することができました。
3. セクション(ページ管理)を導入する
本節ではセクション設定によるページ管理について解説していきます。python-docで、セクション機能を操作することができます。
3.1 セクションとは
Wordにおける「セクション」とはページの管理ユニットです。具体的には、ページまたは、ページ範囲ごとに、ページサイズや余白、用紙の方向、ヘッダー/フッターなどの設定を行うことができます。
例えば、Wordドキュメント全7ページを3つのセクション(A,B,C)に分類してページ管理した場合を図7に示します。このようにページ範囲ごとに、ヘッダー・フッターや用紙の方向などのページ情報を設定・変更することができます。
python-docxではセクションを Sectionオブジェクト で管理しています。
3.2 セクション(Sectionオブジェクト)の取得と設定
Sectionオブジェクトの新規追加および既存のオブジェクトの取得にはDocumentオブジェクト配下のadd_section()メソッド と sectionsプロパティ を使います。
add_section()メソッド の 引数:start_type には WD_SECTION_STARTクラス で定義されているEnumから指定します。Word UIとの対応関係は図8の通りです。
(Word -> “レイアウトメニュー” -> “ページ設定タブ” -> “区切り”)
Sectionオブジェクトの関連属性によってセクションごとに「ページ設定」を細かく指定できます。
Word UIの「ページ設定ダイアログ」上の設定項目がどの属性に対応するのかについては以下を参照ください。
【ページ設定(余白)】
【ページ設定(用紙)】
ここでSectionオブジェクトについて、一つ注意点があります。一つのドキュメントの中に複数のSectionオブジェクトを定義することができますが、デフォルト設定では、これらは全て継承(互いにリンクされた)関係にあります。
つまり、現在のセクションが、一つ前までのセクション定義情報をもつことになり、意図通りの設定にならないことがあります。
それを防ぐためには、次の is_linked_to_previousプロパティ で明示的に継承関係を切る(Falseを設定)必要があります。(※Trueではないので注意して下さい。)
セクションの活用事例として次項では「ヘッダー/フッター」を適用する方法を取り上げます。
3.3 セクションの活用(ヘッダー、フッター設定する)
セクションを活用する目的に、ページの「ヘッダー、フッター」の設定にあることは多いと思います。本項では、「ヘッダー、フッター」設定の具体例を紹介します。
ヘッダー(Headerオブジェクト)とフッター(Footerオブジェクト)は、Sectionオブジェクトの
headerプロパティ と footerプロパティ で取得します。
取得した _Header(_Footer)オブジェクトに対してコンテンツを追加するには、本文作成の時と同じように add_paragraph()メソッド で段落(Paragraph)を追加します。本文の文章作成については<こちら>を参考にして下さい。
その他、ヘッダー(フッター)に関する主なメソッド・属性は以下のとおりです。
_Header(_Footer)オブジェクト | 機能 | その他詳細 |
---|---|---|
add_paragraph(text, style) | 段落を追加する | Paragraphオブジェクト |
add_table(rows, cols, width) | テーブルを追加する | rows:行数, cols:列数, width:横幅 |
is_linked_to_previous | 直前のヘッダー(フッター)情報の継承の可否 | True:有効/False:無効 |
【SAMPLE(4)】
Sectionオブジェクトを使ったコード例を1つ紹介します。
ページの書式設定(用紙サイズ・余白・印刷の向き)とヘッター、フッターをセクション毎に確認・設定しています。
from docx import Document
from docx.enum.section import WD_SECTION
from docx.shared import Mm # 単位系や色が定義されているSharedクラス
from docx.enum.section import WD_ORIENT # ページの向きが定義されているenumrationsクラス
from docx.enum.text import WD_ALIGN_PARAGRAPH
# ドキュメントを新規作成する
doc1 = Document()
# 現在のセクションを取得するにはsectionsプロパティに[-1]を付加する
sec1 = doc1.sections[-1]
# start_typeプロパティで現在のセクションタイプを調べる
# 新規作成されたドキュメントにはデフォルトで1つセクション(NEW_PAGE)を持っている
print(sec1.start_type) # >>NEW_PAGE (2)
#-------------------------------------------------------------------------------------
# セクション1のページの書式を調べる
# セクション1のページ設定(ページの向き、ページの幅、ページの高さ)を取得する
print(sec1.orientation, sec1.page_width.mm, sec1.page_height.mm) # >>PORTRAIT (0) 215.9 279.4
# セクション1のページ設定(ページの余白(左),ページの余白(右))
print(sec1.left_margin.mm, sec1.left_margin.mm) # >> 31.75 31.75
# セクション1のページ設定(ページの余白(上),ページの余白(下))
print(sec1.top_margin.mm, sec1.bottom_margin.mm) # >> 25.4 25.4
#-------------------------------------------------------------------------------------
# セクション1のヘッター・フッターを設定する
# headerプロパティでHeaderオブジェクトを取得する
hd1 = sec1.header
# Headerオブジェクトのadd_paragraph()メソッドで段落を追加する
hd1_pg = hd1.add_paragraph('CONFIDENTIAL_マル秘')
# footerプロパティでFooterオブジェクトを取得する
ft1 = sec1.footer
# Headerオブジェクトのadd_paragraph()メソッドで段落を追加する
ft1_pg = ft1.add_paragraph('株式会社 Pythonでもっと自由を')
# 段落の位置を右端に設定する
ft1_pg.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.RIGHT
#-------------------------------------------------------------------------------------
# セクション2を追加してページの書式を設定する
# add_section()メソッドで新規セクション(NEW_PAGE)を追加する
sec2= doc1.add_section(WD_SECTION.NEW_PAGE)
print(sec2.start_type) # >>NEW_PAGE (2)
# orientationプロパティで印刷の向きを横向きに変更する
sec2.orientation = WD_ORIENT.LANDSCAPE
# セクション2の横幅を設定する
sec2.page_width = Mm(279.4)
# セクション2の縦幅を設定する
sec2.page_height = Mm(215.9)
#-------------------------------------------------------------------------------------
# セクション2のヘッター・フッターを設定する
hd2 = sec2.header
ft2 = sec2.footer
# is_linked_to_previousプロパティで前のセクションのヘッター・フッター
# を引用するかを選択することができる
hd2.is_linked_to_previous = False # セクション1のヘッターを引用しない
ft2.is_linked_to_previous = True # セクション1のフッターを引用する
doc1.save('InsertSection_List4JP.docx')
それでは、ポイントを解説します。
55~66行目でセクションをもう一つ追加しています(変数sec2)。タイプを「NEW_PAGE」にしているので、2ページ目以降にこのセクションが適用されます。
<List4>の実行結果は以下のようになりました(以下からダウンロードできます)。
ページの書式設定(用紙サイズ・余白・用紙の向き)とヘッター、フッターがセクション(ページ)ごとに設定できています。
- 1ページ目(セクション1):ヘッター/フッター有、縦向き
- 2ページ目(セクション2):フッター(セクション1をリンク)、横向き
4. まとめ
いかがでしたでしょうか?
今回は「python-docx」ライブラリによる、画像・テーブル(表)の挿入、それからセクションによるページ管理する方法について解説してきました。
Wordのメインコンテンツはあくまで本文(文章、テキスト)ではあるのですが、図・表を用いることにより、訴求力や信ぴょう性を高めることができます。とりわけ、論文・解説書など、公式でしっかりとしたドキュメントでは尚更です。
また、セクション管理を自動化することで「一度に大量のドキュメントを一括編集」することを可能とします。
ぜひ、貴方のWord作業の効率改善にPythonをお役立てください。
最後に今回の記事のポイントをまとめておきましょう。
➀. python-docxで画像を挿入することができる。Word自身は、画像を2つのレイヤーに挿入可能であるが、このライブラリで対応できるレイヤーは行内(Inline Layer)のみである。Drawing Layerの画像に対応するには別のライブラリや方法を試行する必要がある。
➁. 表(Tableオブジェクト)を作成しドキュメント内に追加することができる。表のスタイルをはじめとする、各種属性が用意されており見栄えを整えることができる。
➂. ページの書式設定やフッター・ヘッターの管理はSectionオブジェクト行われる。専用のプロパティで取得と設定できる。
➃. python-docxでは、図形、スマートアートを操作することはできない。そのため、別のライブラリや方法を試行する必要がある。(今後のアップデートに期待する)
さて次回は、ドキュメントにスタイルを適用する方法について解説します。
Wordで文章を作成する目的は様々です。「公的でフォーマルな文章」であったり「論文口調なかっちちとした文章」または「内々の親しげな口語口調」・・・
このように目的に応じて、事前にある程度文章のスタイル(フォント、見出し、ヘッター)、書き方が決まっているのが普通です。
この「文章の型」を定型スタイルとしてWordに登録しておけば、繰り返し利用ができて効率的です。
次回は、このスタイル機能の活用方法を解説します。どうぞ、お楽しみに!
リンク先はこちらになります。↓
最後までお読みいただきありがとうございました。