0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

実務の「地雷」を突破する —— Pythonによる社内帳票自動化とOutlook操作の記録

0
Posted at

1. はじめに

前任者がPAD(Power Automate Desktop)で構築した業務フローを、保守性と安定性の観点からPythonへ移行しています。

しかし、いざ実装を始めると現場特有の「地雷」が次々と爆発します。
本記事では、特に手強かった 「ガチガチに作り込まれた既存Excelフォーマット」 へのデータ流し込みと、 「APIが使えない制約下でのOutlook操作」 をどう攻略したか、泥臭くも実践的な解決策を全記録として公開します。

2. 遭遇した課題と解決のプロセス

① 「ファイルがあるのに見つからない」パス解決の罠

現象: FileNotFoundError: [Errno 2] No such file or directory が発生。
data/templates/ 配下にファイルは確実に存在するのに、VS Codeの実行環境(カレントディレクトリ)のズレによりファイルが特定できない現象に悩まされました。

解決策: 相対パスやカレントディレクトリに頼るのをやめ、__file__ を基点にプロジェクトルートを自動特定する「盤石な配線」を実装しました。

# src/automation/excel_task.py
from pathlib import Path

class ExcelAutomator:
    def __init__(self, config):
        self.config = config
        # 実行ファイルの位置からプロジェクトルートを絶対パスで特定
        # 例: src/automation/ から2階層上がればルートディレクトリ
        self.project_root = Path(__file__).resolve().parents[2]

    def create_from_format(self, format_key):
        # 設定ファイルの相対パスを、プロジェクトルートからの絶対パスに結合
        f_info = self.config["excel_formats"][format_key]
        template_path = self.project_root / f_info["template"]
        # これで、どこからスクリプトを実行しても確実にファイルを特定可能

② 結合セルへの書き込みエラー(Pandasの限界)

現象: pandasto_excel で既存フォーマットに書き込もうとした際、AttributeError: 'MergedCell' object attribute 'value' is read-only が発生。

原因: 実務の帳票で多用される「悪魔の結合セル」に対し、データ分析ツールのPandasが構造保護のために拒絶反応を示したためです。

解決策: Pandasでの一括処理を諦め、Excel操作に特化した openpyxl で1セルずつ丁寧に「ピンポイント注入」する方式に変更しました。

# openpyxlによる結合セルへの精密書き込み
from openpyxl import load_workbook

def write_to_template(self, template_path, output_path, mapping_data):
    wb = load_workbook(template_path)
    ws = wb.active
    
    # 結合セルであっても、その範囲の「左上のアドレス(B2など)」を指定すれば
    # openpyxlはエラーを出さずに値を保持してくれる
    for cell_address, value in mapping_data.items():
        ws[cell_address] = value
        
    wb.save(output_path)

③ 組織アカウント環境でのOutlook(Web)操作

現象: Microsoft GraphなどのAPIが組織のセキュリティポリシーで使用不可。残された道はブラウザ(RPA的)操作のみ。

解決策: Playwright を採用し、DOM要素(ボタンのクリックなど)ではなく 「ショートカットキー」のエミュレート に全振りしました。
SaaSのUI(ボタンの位置やクラス名)は予告なく変更されますが、ショートカットキー(Nキーで新規作成など)は不変です。
これにより、UI変更に強い堅牢な自動化が実現しました。

# Playwrightによるキーボード操作のエミュレート
def send_report_mail(page, recipient, subject, body):
    page.goto("https://outlook.office.com/mail/")
    # 読み込み完了の目安として要素を待機
    page.wait_for_selector("text=新規メール")

    # DOMをクリックせず、ショートカットキーを駆使して操作
    page.keyboard.press("n")      # 新規作成
    page.keyboard.type(recipient) # 宛先
    page.keyboard.press("Tab")
    page.keyboard.press("Tab")
    page.keyboard.type(subject)   # 件名
    page.keyboard.press("Tab")
    page.keyboard.type(body)      # 本文
    
    page.keyboard.press("Control+Enter") # 送信

3. 運用を楽にする「安全設計」のアイディア

1. セル住所の外部定義 (JSON Mapping)

「どのデータをどのセルに書くか」をPythonコード内に直書きせず、JSONで外部管理しました。
「フォーマットが更新されてB2からC2にズレた」という現場あるあるな変更にも、非エンジニアでもJSONの書き換えだけで即応できます。

{
    "excel_formats": {
        "activity_registration": {
            "template": "data/templates/format_v1.xlsx",
            "mapping": {
                "date": "B2",
                "sales_rep": "D2"
            }
        }
    }
}

2. ログ管理を「メール送信」へ昇華

「ログファイルを書き出しても、エラーが起きるまで誰も見ない」という実態を踏まえ、実行結果を自分宛にメール送信する 機能を実装しました。

  • 即時性: 処理の成功・失敗がスマホやPCにプッシュ通知で届く。
  • 証跡管理: メール履歴がそのまま「いつ何を処理したか」のエビデンスになる。
  • 開発効率: VS Codeの全体検索でログファイルの中身が「ノイズ」として引っかからなくなる。

4. おわりに

モノづくりの現場と同じく、ソフトウェア開発においても「堅牢性の確保(エラーハンドリング)」と「ディレクトリ構造の抽象化(パス管理の集約)」が欠かせません。

PADからの移行は、単にツールを置き換える作業ではなく、Pythonの柔軟性を活かして「よりメンテナンスしやすく、壊れにくい仕組み」へと業務フローを再設計するプロセスです。
同じように社内の自動化で戦っている方の参考になれば幸いです!


技術スタック:

  • Python 3.10
  • PySide6 (GUI)
  • Playwright (Browser Automation)
  • openpyxl (Excel Engine)
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?