非IT企業に勤める中年サラリーマンのIT日記

非IT企業でしかもITとは全く関係ない部署にいる中年エンジニア。唯一の趣味がプログラミングという”自称”プログラマー。

【Python】パワポ自動化:「表」を検出しデータを挿入する方法

   

Pythonを用いてPowerPointファイルを操作するライブラリ「python-pptx」を活用し、スライド内に配置された特定の「表(Table)」をプログラム側から自動検出し、任意のデータを動的に書き換える方法について解説します。既存の表のデザインやフォント、中央揃えといった細かなレイアウトの体裁を維持したまま、テキストだけを安全に上書き・更新する処理です。

こちらが実行イメージです。既存の表にデータが挿入されていることがわかると思います。実際のPythonコードは以下。

 

from pathlib import Path
from pptx import Presentation
from pptx.enum.shapes import MSO_SHAPE_TYPE
from pptx.enum.text import PP_ALIGN
from pptx.oxml.ns import qn

# ==========================================
# 準備:ファイルの読み込みと住所録データの定義
# ==========================================
# ※ 実行する際は、スクリプトと同じフォルダに「format2.pptx」を用意してください。
template_path = Path("format.pptx")
if not template_path.exists():
    raise FileNotFoundError(f"テンプレートファイルが見つかりません: {template_path}")

prs = Presentation(str(template_path))

# 誰もがわかりやすい住所録データ(CSVから1行読み込んだ状態を想定)
csv_row = {
    "EmployeeID": "EMP-00125",
    "Name": "山田 太郎",
    "Department": "開発部",
    "Position": "課長",
    "Phone": "090-1234-5678",
    "Email": "yamada@example.com",
    "Emergency": "03-9876-5432"
}

# 操作対象のスライドを指定(例として3ページ目:index=1 を操作)
slide = prs.slides[1]

# 適用するフォントの定義
FONT_NAME = "BIZ UDPゴシック"

# ==========================================
# 1. スライド内の「表(テーブル)」を探索
# ==========================================
# スライド上のすべてのオブジェクト(図形、テキストボックス、表など)をループで調べます。
for shape in slide.shapes:
    
    # オブジェクトの種類が「表(TABLE)」であるか判定
    if shape.shape_type == MSO_SHAPE_TYPE.TABLE:
        tbl = shape.table
        
        # ------------------------------------------
        # 2. [0行、1列目] のセルに「社員ID」を書き込み
        # ------------------------------------------
        cell_id = tbl.cell(0, 0)
        tf_id = cell_id.text_frame
        
        # セル内の段落を処理(中央揃えとフォント固定の適用)
        for p in tf_id.paragraphs:
            p.alignment = PP_ALIGN.CENTER  # 横方向を「中央揃え」に設定
            
            # 段落内に文字の塊(Run)がない場合は新規作成
            if len(p.runs) == 0:
                r = p.add_run()
                r.text = csv_row["EmployeeID"]
                r.font.name = FONT_NAME
                # XML要素に直接アクセスし、フォント名を設定(文字化けや装飾消失を防ぐバグ対策)
                r._r.get_or_add_rPr().set(qn("a:ea"), FONT_NAME)
                r._r.get_or_add_rPr().set(qn("a:latin"), FONT_NAME)
                r._r.get_or_add_rPr().set(qn("a:cs"), FONT_NAME)
            else:
                # 既にRunがある場合は最初のRunを書き換え、残りをクリア
                p.runs[0].text = csv_row["EmployeeID"]
                p.runs[0].font.name = FONT_NAME
                rPr = p.runs[0]._r.get_or_add_rPr()
                rPr.set(qn("a:ea"), FONT_NAME)
                rPr.set(qn("a:latin"), FONT_NAME)
                rPr.set(qn("a:cs"), FONT_NAME)
                for r in p.runs[1:]:
                    r.text = ""

        # ------------------------------------------
        # 3. マッピング定義に基づいて他のセル(住所録データ)を書き換え
        # ------------------------------------------
        # 書き換えたいセルの位置(行, 列)と、対応するデータのキー(列名)
        mapping = {
            (1, 0): "Name",        # 1行目の0列目 ➔ 氏名
            (1, 1): "Department",  # 1行目の1列目 ➔ 部署
            (1, 2): "Position",    # 1行目の2列目 ➔ 役職
            (2, 0): "Phone",       # 2行目の0列目 ➔ 電話番号
            (2, 1): "Email",       # 2行目の1列目 ➔ メールアドレス
            (2, 2): "Emergency"    # 2行目の2列目 ➔ 緊急連絡先
        }
        
        # マッピングをループ処理して各セルにデータを流し込む
        for (r, c), col in mapping.items():
            val = csv_row.get(col, "")
            text_to_insert = "" if val is None else str(val)
            
            # 対象のセルを取得してテキストフレーム(文字枠)にアクセス
            target_cell = tbl.cell(r, c)
            tf_target = target_cell.text_frame
            
            # 各セルの段落に対して中央揃えとフォントの適用処理を実施
            for p in tf_target.paragraphs:
                p.alignment = PP_ALIGN.CENTER  # 中央揃え
                
                if len(p.runs) == 0:
                    r_new = p.add_run()
                    r_new.text = text_to_insert
                    r_new.font.name = FONT_NAME
                    r_new._r.get_or_add_rPr().set(qn("a:ea"), FONT_NAME)
                    r_new._r.get_or_add_rPr().set(qn("a:latin"), FONT_NAME)
                    r_new._r.get_or_add_rPr().set(qn("a:cs"), FONT_NAME)
                else:
                    p.runs[0].text = text_to_insert
                    p.runs[0].font.name = FONT_NAME
                    rPr = p.runs[0]._r.get_or_add_rPr()
                    rPr.set(qn("a:ea"), FONT_NAME)
                    rPr.set(qn("a:latin"), FONT_NAME)
                    rPr.set(qn("a:cs"), FONT_NAME)
                    # 2つ目以降の余分な文字の塊があれば削除
                    for remaining_run in p.runs[1:]:
                        remaining_run.text = ""

        # スライド内の目的の表を1つ処理できたら、他の図形の探索(ループ)は終了
        break

# ==========================================
# 完了:別名で保存
# ==========================================
output_path = Path("address_replaced_output.pptx")
prs.save(str(output_path))
print(f"住所録表の検出およびテキスト置換が完了しました。保存先: {output_path}")
 

 

スポンサーリンク

 - Python