企業の日常業務において、個人化文書の一括生成は高頻度かつ反復的な作業です。人事部門は新入社員ごとに労働契約書を作成し、財務部門は毎月数十社の顧客向けに請求書を発行し、マーケティング部門は四半期ごとに数百名のパートナーへカスタマイズされた招待状を送付します。これらの文書はフォーマットが完全に同一で、具体的なデータのみ人によって異なります。従来の方法は Word で手動による検索・置換を行うか、Word 標準の差し込み印刷機能を使用することですが、前者は効率が極めて低くエラーが発生しやすく、後者は操作手順が煩雑で自動化プロセスへの統合が困難です。
Python プログラミングによる差し込み印刷を実装することで、「テンプレート + データ = 文書」のプロセスを完全に自動化できます。テンプレートを一度作成し、データを一括で入力するだけで、数分以内に数百件のフォーマット統一・内容正確な個人化文書を生成できます。本記事では Free Spire.Doc for Python を使用して Word 文書で差し込み印刷を実行する方法を説明します。基礎的な差し込み、一括生成、条件フィールド、ネスト差し込み、空領域の処理などのシナリオを網羅し、人事部門での労働契約書一括生成を業務メインラインとして、文書自動化のコアスキルの習得を支援します。
1. 環境準備とライブラリのインストール
まず Free Spire.Doc for Python をインストールします:
pip install spire.doc.free
差し込み印刷のコア考え方は「テンプレート + データ充填」です。テンプレート文書にあらかじめ差し込みフィールド(Merge Field)を挿入しておき、プログラム実行時にこれらのフィールドを実際のデータに置き換えます。以下では、差し込みフィールドを含む労働契約書テンプレートを作成します:
from spire.doc import *
from spire.doc.common import *
# 労働契約書テンプレートを作成
document = Document()
section = document.AddSection()
# タイトルを追加
paragraph = section.AddParagraph()
paragraph.AppendText("労働契約書")
paragraph.Style = document.Styles.get_Item("Heading1")
paragraph.Format.HorizontalAlignment = HorizontalAlignment.Center
# 本文段落を追加し、差し込みフィールドを挿入
paragraph = section.AddParagraph()
paragraph.AppendText("甲方(雇用主):")
paragraph.AppendField("CompanyName", FieldType.FieldMergeField)
paragraph = section.AddParagraph()
paragraph.AppendText("乙方(労働者):")
paragraph.AppendField("EmployeeName", FieldType.FieldMergeField)
paragraph = section.AddParagraph()
paragraph.AppendText("個人番号:")
paragraph.AppendField("IDNumber", FieldType.FieldMergeField)
paragraph = section.AddParagraph()
paragraph.AppendText("入社日:")
paragraph.AppendField("HireDate", FieldType.FieldMergeField)
paragraph = section.AddParagraph()
paragraph.AppendText("役職:")
paragraph.AppendField("Position", FieldType.FieldMergeField)
paragraph = section.AddParagraph()
paragraph.AppendText("月給(元):")
paragraph.AppendField("Salary", FieldType.FieldMergeField)
# テンプレートを保存
document.SaveToFile("ContractTemplate.docx", FileFormat.Docx)
document.Close()
print("テンプレート作成完了:ContractTemplate.docx")
解説:
-
Documentオブジェクトは Word 文書全体を表し、AddSection()でセクション(Section)を追加します。 -
AppendField("FieldName", FieldType.FieldMergeField)は現在の段落に差し込みフィールドを挿入します。フィールド名はFieldNameです。 - 差し込みフィールドは Word 上で
«FieldName»と表示され、差し込み印刷の実行後に実際のデータに置き換えられます。 - テンプレートは一度作成すれば繰り返し使用可能で、テンプレートのフォーマットを変更してもデータ充填ロジックに影響しません。
2. 基礎的な差し込み印刷:単一契約書の生成
テンプレートが完成したら、最も基礎的な操作はデータをテンプレートに充填し、個人化文書を生成することです。
from spire.doc import *
from spire.doc.common import *
# テンプレートを読み込み
document = Document()
document.LoadFromFile("ContractTemplate.docx")
# 差し込みフィールド名と対応する値を定義
fieldNames = ["CompanyName", "EmployeeName", "IDNumber", "HireDate", "Position", "Salary"]
fieldValues = ["上海智遠科技有限公司", "田中", "310101199001011234", "2026年3月15日", "シニアソフトウェアエンジニア", "25000"]
# 差し込み印刷を実行
document.MailMerge.Execute(fieldNames, fieldValues)
# 差し込み完了後の文書を保存
document.SaveToFile("Contract_田中.docx", FileFormat.Docx)
document.Close()
print("契約書生成完了:Contract_田中.docx")
解説:
-
document.LoadFromFile()はあらかじめ作成したテンプレートファイルを読み込みます。 -
fieldNames配列の名前はテンプレート内の差し込みフィールド名と完全に一致する必要があります(大文字小文字を区別)。 -
fieldValues配列の値はfieldNamesの各フィールドに順序対応します。 -
MailMerge.Execute()はコアメソッドで、すべてのデータをテンプレートに一括充填します。 - 差し込み完了後、テンプレート内の
«CompanyName»は「上海智遠科技有限公司」に置き換えられ、«EmployeeName»は「田中」に置き換えられ、以降も同様です。
3. 一括差し込み印刷:複数契約書の一括生成
実際の業務では、HR は複数名の新入社員の契約書を一度に生成する必要がよくあります。ループで差し込み印刷を呼び出すことで、一括生成が容易に実現できます。
from spire.doc import *
from spire.doc.common import *
# 社員データリスト
employees = [
{
"CompanyName": "上海智遠科技有限公司",
"EmployeeName": "田中",
"IDNumber": "310101199001011234",
"HireDate": "2026年3月15日",
"Position": "シニアソフトウェアエンジニア",
"Salary": "25000"
},
{
"CompanyName": "上海智遠科技有限公司",
"EmployeeName": "佐藤",
"IDNumber": "310104199203032345",
"HireDate": "2026年3月15日",
"Position": "プロダクトマネージャー",
"Salary": "22000"
},
{
"CompanyName": "上海智遠科技有限公司",
"EmployeeName": "鈴木",
"IDNumber": "310105198807073456",
"HireDate": "2026年3月20日",
"Position": "テストエンジニア",
"Salary": "18000"
},
{
"CompanyName": "上海智遠科技有限公司",
"EmployeeName": "高橋",
"IDNumber": "310106199505054567",
"HireDate": "2026年4月1日",
"Position": "UIデザイナー",
"Salary": "16000"
},
{
"CompanyName": "上海智遠科技有限公司",
"EmployeeName": "渡辺",
"IDNumber": "310108199101015678",
"HireDate": "2026年4月1日",
"Position": "データアナリスト",
"Salary": "20000"
},
]
fieldNames = ["CompanyName", "EmployeeName", "IDNumber", "HireDate", "Position", "Salary"]
# 契約書を一括生成
for emp in employees:
document = Document()
document.LoadFromFile("ContractTemplate.docx")
fieldValues = [emp[name] for name in fieldNames]
document.MailMerge.Execute(fieldNames, fieldValues)
output_file = f"Contract_{emp['EmployeeName']}.docx"
document.SaveToFile(output_file, FileFormat.Docx)
document.Close()
print(f"生成完了:{output_file}")
print(f"計 {len(employees)} 件の契約書を生成")
解説:
- 各ループでテンプレートファイルを再読み込みし、差し込みフィールドが前回の差し込みで消費されていないことを保証します。
-
fieldValuesはリスト内包表記で社員辞書からfieldNamesの順序で値を抽出します。 - 出力ファイル名に社員名を含め、アーカイブと検索に便利です。
- 5 件の契約書が数秒で全て生成され、手動操作に比べて数時間を節約できます。
4. 条件フィールド:テンプレートに IF ロジックを組み込む
一部の契約条項は条件に応じて動的に表示する必要があります。例えば、月給が 20000 元を超える社員には守秘義務契約条項を付加します。IF 条件フィールドを使用することでこの要件を実現できます。
from spire.doc import *
from spire.doc.common import *
def create_if_field(document, paragraph):
"""段落に IF 条件フィールドを作成"""
ifField = IfField(document)
ifField.Type = FieldType.FieldIf
ifField.Code = "IF "
paragraph.Items.Add(ifField)
# 条件:Salary > "20000"
paragraph.AppendField("Salary", FieldType.FieldMergeField)
paragraph.AppendText(" > ")
paragraph.AppendText("\"20000\" ")
# 条件満足時に表示するテキスト
paragraph.AppendText("\"特別提示:乙方は役職が核心的商業秘密に関わるため、別途《秘密保持及び競業制限協議》に署名する必要があります。\" ")
# 条件不満足時に表示するテキスト
paragraph.AppendText("\"\"")
# フィールド終了マークを追加
end = document.CreateParagraphItem(ParagraphItemType.FieldMark)
tempFieldMark = end if isinstance(end, FieldMark) else None
if tempFieldMark is not None:
tempFieldMark.Type = FieldMarkType.FieldEnd
paragraph.Items.Add(end)
ifField.End = end if isinstance(end, FieldMark) else None
# 条件フィールド付きテンプレートを作成
document = Document()
section = document.AddSection()
# 基礎情報段落
paragraph = section.AddParagraph()
paragraph.AppendText("甲方:")
paragraph.AppendField("CompanyName", FieldType.FieldMergeField)
paragraph = section.AddParagraph()
paragraph.AppendText("乙方:")
paragraph.AppendField("EmployeeName", FieldType.FieldMergeField)
paragraph = section.AddParagraph()
paragraph.AppendText("月給:")
paragraph.AppendField("Salary", FieldType.FieldMergeField)
paragraph.AppendText(" 元")
# 条件段落
paragraph = section.AddParagraph()
create_if_field(document, paragraph)
# 差し込み印刷を実行
fieldNames = ["CompanyName", "EmployeeName", "Salary"]
fieldValues = ["上海智遠科技有限公司", "田中", "25000"]
document.MailMerge.Execute(fieldNames, fieldValues)
document.IsUpdateFields = True
document.SaveToFile("ContractWithCondition.docx", FileFormat.Docx)
document.Close()
print("条件フィールド付き契約書生成完了")
解説:
-
IfFieldは条件フィールドオブジェクトで、TypeをFieldType.FieldIfに設定します。 - 条件式は
IF «Salary» > "20000" "満足時テキスト" "不満足時テキスト"です。 -
paragraph.AppendField("Salary", FieldType.FieldMergeField)は IF 条件内で差し込みフィールドを参照します。 -
document.IsUpdateFields = Trueは差し込み後にフィールドが正しく更新・表示されることを保証します。 - 田中の月給は 25000 元(>20000)のため、契約書に守秘義務の提示が自動的に表示されます。月給が 18000 元の場合、当該段落は空になります。
5. 空領域の非表示:未充填差し込みフィールドのクリーンアップ
一部のフィールドにデータがない場合、差し込み後に文書に空段落や空フィールドが残ります。空領域非表示オプションを設定することで、これらの内容を自動的にクリーンアップし、文書をより整然とさせることができます。
from spire.doc import *
from spire.doc.common import *
# オプションフィールド付きテンプレートを作成
document = Document()
section = document.AddSection()
paragraph = section.AddParagraph()
paragraph.AppendText("社員名:")
paragraph.AppendField("EmployeeName", FieldType.FieldMergeField)
paragraph = section.AddParagraph()
paragraph.AppendText("緊急連絡先:")
paragraph.AppendField("EmergencyContact", FieldType.FieldMergeField)
paragraph = section.AddParagraph()
paragraph.AppendText("緊急連絡先電話番号:")
paragraph.AppendField("EmergencyPhone", FieldType.FieldMergeField)
document.SaveToFile("TemplateWithOptional.docx", FileFormat.Docx)
document.Close()
# テンプレートを読み込み差し込みを実行(一部フィールドにデータなし)
document = Document()
document.LoadFromFile("TemplateWithOptional.docx")
fieldNames = ["EmployeeName", "EmergencyContact", "EmergencyPhone"]
# 緊急連絡先と電話番号は空
fieldValues = ["田中", "", ""]
# 空領域非表示を有効化
document.MailMerge.HideEmptyParagraphs = True
document.MailMerge.HideEmptyGroup = True
document.MailMerge.Execute(fieldNames, fieldValues)
document.SaveToFile("ContractHideEmpty.docx", FileFormat.Docx)
document.Close()
print("空領域非表示の契約書生成完了")
解説:
-
MailMerge.HideEmptyParagraphs = True:差し込み後、値が空の段落は自動的に削除されます。 -
MailMerge.HideEmptyGroup = True:差し込み後、値が空のグループは自動的に削除されます。 - このオプションを有効にしない場合、「緊急連絡先:」と「緊急連絡先電話番号:」の2行は残りますが内容が空で、文書の美観に影響します。
- 有効化後、これらの2行は完全に削除され、文書にはデータがある部分のみが保持されます。
6. ネスト差し込み印刷:主従関係データの処理
ネスト差し込み印刷は主従関係のデータ構造を処理するために使用します。例えば、社員契約書にその社員のすべての福利厚生項目を列記する必要がある場合、社員が主テーブル、福利厚生が従テーブルになります。
from spire.doc import *
from spire.doc.common import *
# ネスト差し込みテンプレートを作成
document = Document()
section = document.AddSection()
# 主領域:社員情報
paragraph = section.AddParagraph()
paragraph.AppendText("社員名:")
paragraph.AppendField("EmployeeName", FieldType.FieldMergeField)
paragraph = section.AddParagraph()
paragraph.AppendText("部門:")
paragraph.AppendField("Department", FieldType.FieldMergeField)
# ネスト領域:福利厚生明細
paragraph = section.AddParagraph()
paragraph.AppendText("福利厚生明細:")
# TableStart と TableEnd でネスト領域をマーク
paragraph = section.AddParagraph()
paragraph.AppendField("Benefits.TableStart:Benefit", FieldType.FieldMergeField)
paragraph.AppendText(" - ")
paragraph.AppendField("Benefits.BenefitName", FieldType.FieldMergeField)
paragraph.AppendText("(")
paragraph.AppendField("Benefits.Amount", FieldType.FieldMergeField)
paragraph.AppendText(" 元)")
paragraph.AppendField("Benefits.TableEnd:Benefit", FieldType.FieldMergeField)
document.SaveToFile("NestedMergeTemplate.docx", FileFormat.Docx)
document.Close()
# XML データでネスト差し込みを実行
document = Document()
document.LoadFromFile("NestedMergeTemplate.docx")
# ネスト領域マッピングを定義
regionDict = {"Benefits": "Employee_Id = %Employee.Employee_Id%"}
# ネスト差し込み印刷を実行(XML データファイルが必要)
# document.MailMerge.ExecuteWidthNestedRegion("BenefitsData.xml", regionDict)
# デモ:簡単な差し込みで代替
fieldNames = ["EmployeeName", "Department"]
fieldValues = ["田中", "研究開発部"]
document.MailMerge.Execute(fieldNames, fieldValues)
document.SaveToFile("NestedMergeResult.docx", FileFormat.Docx)
document.Close()
print("ネスト差し込み文書生成完了")
解説:
-
TableStart:TableNameとTableEnd:TableNameはネスト領域の開始と終了をマークします。 -
ExecuteWidthNestedRegion(dataFile, regionDict)メソッドはネスト差し込みを実行するために使用し、dataFileは XML データファイルのパスです。 -
regionDictは主従関係を定義します。例えば"Benefits": "Employee_Id = %Employee.Employee_Id%"は Benefits 領域が Employee_Id フィールドを通じて主テーブル Employee と関連付くことを示します。 - ネスト差し込みは注文-注文明細、社員-福利厚生項目、契約-支払計画などの主従データ構造に適しています。
7. 差し込みフィールド名の識別:テンプレートフィールドの確認
他の人が作成したテンプレートを処理する場合、テンプレートにどのような差し込みフィールドが含まれているかを事前に把握し、対応するデータを準備する必要がよくあります。Spire.Doc は差し込みフィールド名を取得する API を提供しています。
from spire.doc import *
from spire.doc.common import *
# テンプレートを読み込み
document = Document()
document.LoadFromFile("ContractTemplate.docx")
# すべての差し込みフィールド名を取得
mergeFieldNames = document.MailMerge.GetMergeFieldNames()
print("テンプレートに含まれる差し込みフィールド:")
print("-" * 40)
for i, name in enumerate(mergeFieldNames, start=1):
print(f" {i}. {name}")
print("-" * 40)
print(f"計 {len(mergeFieldNames)} 個の差し込みフィールド")
# 特定フィールドの存在確認
required_fields = ["CompanyName", "EmployeeName", "IDNumber", "HireDate", "Position", "Salary"]
missing_fields = [f for f in required_fields if f not in mergeFieldNames]
if missing_fields:
print(f"警告:以下の必須フィールドがテンプレートに存在しません:{missing_fields}")
else:
print("すべての必須フィールドがテンプレートに存在します")
document.Close()
解説:
-
GetMergeFieldNames()はテンプレート内のすべての差し込みフィールド名のリストを返します。 -
GetMergeGroupNames()はすべてのグループ名を返し、ネスト差し込みシナリオで使用します。 -
GetMergeFieldNames("GroupName")は指定グループ内の差し込みフィールド名を返します。 - この機能は外部テンプレートの連携やテンプレートの完全性検証に非常に有用で、差し込み前にデータとテンプレートの一致を確認できます。
8. 総合応用:完全な HR 契約書一括生成システム
上記の機能を組み合わせ、完全な HR 契約書一括生成プロセスを構築します。テンプレート作成、データ充填、条件判断から空領域クリーンアップまで、一度の実行ですべての操作を完了します。
from spire.doc import *
from spire.doc.common import *
# ========== ステップ1:契約書テンプレート作成 ==========
def create_template():
document = Document()
section = document.AddSection()
# タイトル
p = section.AddParagraph()
p.AppendText("労働契約書")
p.Style = document.Styles.get_Item("Heading1")
p.Format.HorizontalAlignment = HorizontalAlignment.Center
# 基本情報
fields = [
("甲方(雇用主):", "CompanyName"),
("乙方(労働者):", "EmployeeName"),
("個人番号:", "IDNumber"),
("入社日:", "HireDate"),
("役職:", "Position"),
("月給(元):", "Salary"),
("緊急連絡先:", "EmergencyContact"),
("緊急連絡先電話番号:", "EmergencyPhone"),
]
for label, field_name in fields:
p = section.AddParagraph()
p.AppendText(label)
p.AppendField(field_name, FieldType.FieldMergeField)
document.SaveToFile("HRContractTemplate.docx", FileFormat.Docx)
document.Close()
print("ステップ1完了:テンプレート作成完了")
# ========== ステップ2:契約書一括生成 ==========
def generate_contracts(employees):
field_names = [
"CompanyName", "EmployeeName", "IDNumber", "HireDate",
"Position", "Salary", "EmergencyContact", "EmergencyPhone"
]
success_count = 0
for emp in employees:
document = Document()
document.LoadFromFile("HRContractTemplate.docx")
# 空領域非表示
document.MailMerge.HideEmptyParagraphs = True
document.MailMerge.HideEmptyGroup = True
# データ抽出
field_values = [emp.get(name, "") for name in field_names]
# 差し込み実行
document.MailMerge.Execute(field_names, field_values)
# 保存
output_file = f"HRContract_{emp['EmployeeName']}.docx"
document.SaveToFile(output_file, FileFormat.Docx)
document.Close()
success_count += 1
print(f" 生成完了:{output_file}")
print(f"ステップ2完了:計 {success_count} 件の契約書を生成")
# ========== ステップ3:実行 ==========
# 社員データ
employees = [
{"CompanyName": "上海智遠科技有限公司", "EmployeeName": "田中",
"IDNumber": "310101199001011234", "HireDate": "2026年3月15日",
"Position": "シニアソフトウェアエンジニア", "Salary": "25000",
"EmergencyContact": "田中父", "EmergencyPhone": "13800001111"},
{"CompanyName": "上海智遠科技有限公司", "EmployeeName": "佐藤",
"IDNumber": "310104199203032345", "HireDate": "2026年3月15日",
"Position": "プロダクトマネージャー", "Salary": "22000",
"EmergencyContact": "", "EmergencyPhone": ""},
{"CompanyName": "上海智遠科技有限公司", "EmployeeName": "鈴木",
"IDNumber": "310105198807073456", "HireDate": "2026年3月20日",
"Position": "テストエンジニア", "Salary": "18000",
"EmergencyContact": "鈴木母", "EmergencyPhone": "13900002222"},
]
print("労働契約書の一括生成を開始...")
print("=" * 50)
create_template()
generate_contracts(employees)
print("=" * 50)
print("全て完了!")
解説:
-
create_template()関数はすべてのフィールドを含む契約書テンプレートを一度に作成します。 -
generate_contracts()関数は各社員の契約書をループで生成し、空領域を自動的に非表示にします。 - 佐藤の緊急連絡先と電話番号は空のため、差し込み後にこれらの2行は自動的に削除され、契約書全体のフォーマットに影響しません。
- プロセス全体はテンプレート作成から一括生成まで一度の実行で完了し、HR システムの自動化パイプラインへの統合に適しています。
9. 主要クラスとメソッドの解説
コアクラス
| クラス名 | 説明 |
|---|---|
Document |
Word 文書オブジェクト、読み込み・保存・差し込み印刷操作を担当 |
Section |
文書セクション、段落・テーブルなどのコンテンツを含む |
Paragraph |
段落オブジェクト、テキストと差し込みフィールドの追加に使用 |
MailMerge |
差し込み印刷オブジェクト、差し込み実行と設定メソッドを提供 |
IfField |
条件フィールドオブジェクト、テンプレートに IF ロジックを組み込むために使用 |
差し込み印刷コアメソッド
| メソッド | 説明 |
|---|---|
MailMerge.Execute(fieldNames, fieldValues) |
基礎的な差し込み印刷を実行し、データをテンプレートに充填 |
MailMerge.ExecuteWidthNestedRegion(dataFile, regionDict) |
ネスト差し込み印刷を実行し、主従関係データを処理 |
MailMerge.GetMergeFieldNames() |
テンプレート内のすべての差し込みフィールド名を取得 |
MailMerge.GetMergeGroupNames() |
テンプレート内のすべてのグループ名を取得 |
MailMerge.GetMergeFieldNames(groupName) |
指定グループ内の差し込みフィールド名を取得 |
差し込み印刷設定プロパティ
| プロパティ | 説明 |
|---|---|
MailMerge.HideEmptyParagraphs |
True に設定すると値が空の段落を非表示 |
MailMerge.HideEmptyGroup |
True に設定すると値が空のグループを非表示 |
IsUpdateFields |
True に設定するとすべてのフィールドを更新(条件フィールド用) |
段落操作メソッド
| メソッド | 説明 |
|---|---|
AppendText(text) |
段落末尾にテキストを追加 |
AppendField(name, fieldType) |
段落末尾に差し込みフィールドを追加 |
AppendField(name, FieldType.FieldMergeField) |
差し込み印刷フィールドを追加 |
ファイルフォーマット列挙型
| 列挙値 | 説明 |
|---|---|
FileFormat.Docx |
Word 2007+ フォーマット(.docx) |
FileFormat.Doc |
Word 97-2003 フォーマット(.doc) |
FileFormat.PDF |
PDF フォーマット |
10. まとめ
本記事のサンプルを通じて、Free Spire.Doc for Python を使用して Word 文書で差し込み印刷を実行する方法を理解できたはずです。基礎的な差し込み、一括生成、条件フィールド、ネスト差し込みから空領域処理まで、プロセス全体が高度に自動化されており、HR 契約書生成、財務請求書発行、マーケティング招待状送付など個人化文書の一括生成が必要なシナリオに特に適しています。
差し込み印刷のコア優位性は「テンプレートとデータの分離」にあります。テンプレートは文書のフォーマットとレイアウトの定義を担当し、データは具体的な内容の充填を担当します。この分離により、非技術者はテンプレートのスタイルを独立して変更でき、開発者はデータロジックのみを維持すればよく、両者は互いに干渉しません。この基盤の上にさらに拡張可能で、例えば Excel やデータベースから社員データを読み込み、差し込み後に自動的に PDF に変換し、メール API で生成された文書を自動送信するなど、完全な文書自動化パイプラインを構築できます。
契約書、請求書、招待状などの一括文書生成要件を処理している場合、この Python ベースの差し込み印刷ソリューションは作業効率を顕著に向上させます。Free Spire.Doc for Python の公式ドキュメントはより多くの API リファレンスを提供しています:Free Spire.Doc for Python ドキュメント。


