docx-processing について
コードによるWord文書の生成、データ入力、変換を支援するスキルで、文書自動化に適しています。python-docxとdocxtplを扱い、文書を直接作成する方法とテンプレートを使う方法を選べます。
主な機能
- 01python-docxによる文書作成
- 02docxtplによるテンプレート入力
- 03スタイル、表、ヘッダー、フッターの制御
- 04メールマージ文書の一括生成
- 05DOCXからPDFへの変換計画
活用シーン
- 01書式付きレポートの生成
- 02固定レイアウトのテンプレートへのデータ入力
- 03個別宛ての手紙の一括作成
- 04Word文書のPDF変換
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ pixel-process-ug/ superkit-agents --skill docx-processingインストール後、Claude Code で/docx-processingを入力して読み込まれたか確認します。
詳細
DOCX 処理
概要
Word 文書をプログラムで生成、操作し、テンプレート化します。このスキルでは、文書を直接作成するための python-docx、Jinja2 ベースのテンプレート入力に使用する docxtpl、書式設定の制御(見出し、表、画像、ヘッダー/フッター)、差し込み印刷、スタイル管理、変換方法を扱います。
Word 文書を手作業で編集せず、コードで作成、入力、変換する必要がある場合は、このスキルを適用してください。
複数フェーズのプロセス
フェーズ 1:要件
- ゼロから作成するか、テンプレートに入力するかを判断します
- 文書の構成(セクション、ヘッダー、表、画像)を特定します
- データソース(JSON、CSV、データベース、API)を定義します
- スタイル要件(フォント、色、余白)を計画します
- 出力形式(DOCX、PDF への変換が必要か)を決定します
停止 — 方法(ゼロから作成するか、テンプレートを使うか)を決定し、データソースを確認するまで、実装を始めないでください。
フェーズ 2:実装
- 文書テンプレートを設定するか、ゼロから作成します
- データのバインドとコンテンツの生成を実装します
- 書式とスタイルを適用します
- ヘッダー、フッター、ページ番号を追加します
- 画像と埋め込みオブジェクトを処理します
停止 — 文書のすべてのセクションを実装するまで、検証に進まないでください。
フェーズ 3:検証
- Word/LibreOffice で文書が正しく表示されることを確認します
- ページ間で書式の一貫性を確認します
- 生成した文書のデータが正確であることを検証します
- エッジケース(長いテキスト、欠損データ、特殊文字)でテストします
- 必要に応じて PDF への変換を確認します
アプローチ選択表
| シナリオ | アプローチ | ライブラリ | 理由 |
|---|---|---|---|
| 単発のレポート生成 | ゼロから作成 | python-docx | プログラムによる完全な制御 |
| 固定レイアウトの定期レポート | テンプレート | docxtpl | Word でレイアウトを設計し、データを入力 |
| 大量のレター生成(差し込み印刷) | テンプレート | docxtpl | 1 つのテンプレートから多数の出力を生成 |
| 複雑な書式設定、カスタムスタイル | ゼロから作成 | python-docx | 文書モデルに直接アクセス |
| 技術者以外がテンプレートを設計 | テンプレート | docxtpl | ユーザーが Word で編集し、開発者がデータをバインド |
| PDF 出力が必要 | どちらでも可+変換 | libreoffice / docx2pdf | 後処理ステップ |
python-docx のパターン
文書の作成
from docx import Document
from docx.shared import Inches, Pt, Cm, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_TABLE_ALIGNMENT
doc = Document()
# Set default font
style = doc.styles['Normal']
font = style.font
font.name = 'Calibri'
font.size = Pt(11)
# Add heading
doc.add_heading('Monthly Report', level=0)
# Add paragraph with formatting
para = doc.add_paragraph()
run = para.add_run('Important: ')
run.bold = True
run.font.color.rgb = RGBColor(0xCC, 0x00, 0x00)
para.add_run('This section requires attention.')
# Add table
table = doc.add_table(rows=1, cols=3, style='Light Grid Accent 1')
hdr_cells = table.rows[0].cells
hdr_cells[0].text = 'Name'
hdr_cells[1].text = 'Department'
hdr_cells[2].text = 'Revenue'
for name, dept, rev in data:
row_cells = table.add_row().cells
row_cells[0].text = name
row_cells[1].text = dept
row_cells[2].text = f'${rev:,.2f}'
# Add image
doc.add_picture('chart.png', width=Inches(5.5))
# Save
doc.save('report.docx')
ヘッダーとフッター
from docx.enum.section import WD_ORIENT
from docx.oxml.ns import qn
from docx.oxml import OxmlElement
section = doc.sections[0]
# Page setup
section.page_width = Cm(21)
section.page_height = Cm(29.7)
section.left_margin = Cm(2.5)
section.right_margin = Cm(2.5)
section.top_margin = Cm(2.5)
section.bottom_margin = Cm(2.5)
# Header
header = section.header
header_para = header.paragraphs[0]
header_para.text = 'Company Name — Confidential'
header_para.alignment = WD_ALIGN_PARAGRAPH.RIGHT
header_para.style.font.size = Pt(9)
header_para.style.font.color.rgb = RGBColor(0x88, 0x88, 0x88)
# Footer with page numbers
footer = section.footer
footer_para = footer.paragraphs[0]
footer_para.alignment = WD_ALIGN_PARAGRAPH.CENTER
# Add page number field
run = footer_para.add_run()
fldChar = OxmlElement('w:fldChar')
fldChar.set(qn('w:fldCharType'), 'begin')
run._r.append(fldChar)
run2 = footer_para.add_run()
instrText = OxmlElement('w:instrText')
instrText.set(qn('xml:space'), 'preserve')
instrText.text = ' PAGE '
run2._r.append(instrText)
run3 = footer_para.add_run()
fldChar2 = OxmlElement('w:fldChar')
fldChar2.set(qn('w:fldCharType'), 'end')
run3._r.append(fldChar2)
表の書式設定
from docx.shared import Cm, Pt
from docx.oxml.ns import nsdecls
from docx.oxml import parse_xml
# Set column widths
table.columns[0].width = Cm(4)
table.columns[1].width = Cm(6)
table.columns[2].width = Cm(3)
# Cell shading
for cell in table.rows[0].cells:
shading = parse_xml(f'<w:shd {nsdecls("w")} w:fill="2F5496"/>')
cell._tc.get_or_add_tcPr().append(shading)
for paragraph in cell.paragraphs:
for run in paragraph.runs:
run.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
run.font.bold = True
# Cell alignment
for row in table.rows:
for cell in row.cells:
cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
docxtpl のテンプレートパターン
テンプレート構文(Jinja2)
Template file (template.docx) contains:
{{ company_name }}
Date: {{ report_date }}
Dear {{ recipient_name }},
{% for item in items %}
- {{ item.name }}: ${{ item.price }}
{% endfor %}
Total: ${{ total }}
{%if urgent %}
URGENT: This requires immediate attention.
{%endif %}
テンプレートのレンダリング
from docxtpl import DocxTemplate, InlineImage
from docx.shared import Mm
tpl = DocxTemplate('template.docx')
context = {
'company_name': 'Acme Corp',
'report_date': '2025-03-15',
'recipient_name': 'Alice Johnson',
'items': [
{'name': 'Widget A', 'price': '29.99'},
{'name': 'Widget B', 'price': '49.99'},
],
'total': '79.98',
'urgent': True,
'chart': InlineImage(tpl, 'chart.png', width=Mm(120)),
}
tpl.render(context)
tpl.save('output.docx')
テンプレート内のリッチテキスト
from docxtpl import RichText
rt = RichText()
rt.add('Normal text ')
rt.add('bold text', bold=True)
rt.add(' and ')
rt.add('red text', color='FF0000')
rt.add(' with ')
rt.add('a link', url_id=tpl.build_url_id('https://example.com'))
context = {'formatted_text': rt}
テンプレート内の表
Template table row with loop:
{% tr for row in table_data %}
{{ row.name }} | {{ row.value }} | {{ row.status }}
{% endtr %}
差し込み印刷
from docxtpl import DocxTemplate
import csv
template = DocxTemplate('letter_template.docx')
with open('recipients.csv') as f:
reader = csv.DictReader(f)
for i, row in enumerate(reader):
context = {
'name': row['name'],
'address': row['address'],
'amount': row['amount'],
'due_date': row['due_date'],
}
template.render(context)
template.save(f'letters/letter_{i:04d}_{row["name"]}.docx')
template = DocxTemplate('letter_template.docx') # Re-load for next iteration
スタイル管理
カスタムスタイル
from docx.enum.style import WD_STYLE_TYPE
# Create custom paragraph style
style = doc.styles.add_style('CustomHeading', WD_STYLE_TYPE.PARAGRAPH)
style.font.name = 'Arial'
style.font.size = Pt(16)
style.font.bold = True
style.font.color.rgb = RGBColor(0x2F, 0x54, 0x96)
style.paragraph_format.space_before = Pt(12)
style.paragraph_format.space_after = Pt(6)
# Apply custom style
doc.add_paragraph('Section Title', style='CustomHeading')
スタイルの継承
Normal → Heading 1 → Heading 2 → ...
Normal → Body Text → List Paragraph
Normal → Table Normal → Table Grid
変換方法
DOCX から PDF への変換
# Option 1: LibreOffice (most reliable, server-friendly)
import subprocess
subprocess.run([
'libreoffice', '--headless', '--convert-to', 'pdf',
'--outdir', output_dir, input_file
])
# Option 2: docx2pdf (Windows/macOS with Word installed)
from docx2pdf import convert
convert('input.docx', 'output.pdf')
# Option 3: Generate PDF directly with reportlab for full control
エラー処理
import jinja2
def safe_generate_document(template_path, context, output_path):
try:
tpl = DocxTemplate(template_path)
tpl.render(context)
tpl.save(output_path)
return True
except jinja2.UndefinedError as e:
print(f"Missing template variable: {e}")
return False
except FileNotFoundError as e:
print(f"Template not found: {e}")
return False
except Exception as e:
print(f"Document generation failed: {e}")
return False
アンチパターン/よくある間違い
| アンチパターン | 問題が起きる理由 | 代わりに行うこと |
|---|---|---|
| スタイルを使わず、フォントサイズをハードコードする | 書式に一貫性がなく、保守が困難になります | スタイルを一度定義し、すべての箇所に適用します |
| 欠損したテンプレート変数を処理しない | データが不完全な場合に実行時エラーが発生します | jinja2.Undefined またはデフォルトフィルターを使用します |
| ページ分割を考慮せず、大きな表を作成する | 出力が読みにくくなり、レイアウトが崩れます | ページをまたいで表を分割するか、要約します |
| 絶対画像パスを使用する | 環境間の移植性が損なわれます | 相対パスを使用するか、画像を埋め込みます |
| 異なるバージョンの Word でテストしない | 書式が気付かないうちに崩れます | Word、LibreOffice、Google Docs でテストします |
| API があるのに XML を直接変更する | 壊れやすく、バージョンに依存するコードになります | まず python-docx の API メソッドを使用します |
| スタイルを使わず、すべてを直接書式設定する | 一貫性を保つことができません | 名前付きスタイルを作成して適用します |
| Unicode 文字を無視する | 生成した文書で文字化けが発生します | アクセント付き文字、CJK、記号でテストします |
| 差し込み印刷でテンプレートを再読み込みしない | 最初のレンダリング後に出力が破損します | 反復ごとに DocxTemplate を再インスタンス化します |
合理化を防ぐガード
- アプローチの決定(スクラッチ作成かテンプレートか)を省略しないでください。実装全体がこれによって決まります。
- 少なくとも Word と別のビューアー 1 つでテストせずに、ドキュメントを生成しないでください。
- データの欠落を無視しないでください。空または null のフィールドは、デフォルト値または条件付きセクションで処理してください。
- 本番環境のドキュメント生成パイプラインで、エラー処理を省略しないでください。
- スタイルを使用できる場合は、書式をハードコードしないでください。
統合ポイント
| スキル | 連携方法 |
|---|---|
pdf-processing | DOCX から PDF への変換、または PDF を直接生成する方法の選択 |
xlsx-processing | Excel のデータをドキュメント生成コンテキストに取り込みます |
email-composer | 生成したドキュメントをビジネスメールに添付します |
content-research-writer | 調査内容をホワイトペーパーやレポート用に整形します |
file-organizer | 出力ファイルの命名規則とディレクトリー構成 |
deployment | CI/CD またはサーバー環境でのドキュメント生成パイプライン |
スキルの種類
柔軟 — ドキュメントの複雑さに応じて、python-docx(プログラムによる生成)と docxtpl(テンプレートベース)を選択します。シンプルなレポートではテンプレートが不要な場合もありますが、複雑で繰り返し作成するドキュメントにはテンプレートが適しています。
コメント
Markdown 対応