Pythonで業務自動化|ファイル操作・メール送信・Excel処理の実践スクリプト集

kento_morota 22分で読めます

日々の業務には、ファイルの整理、Excelレポートの作成、メールの一括送信など、繰り返しの定型作業が多く存在します。こうした作業を手動で行い続けると、時間の浪費だけでなく、ヒューマンエラーのリスクも高まります。

Pythonは、こうした業務の自動化に最適なプログラミング言語です。標準ライブラリとサードパーティパッケージを組み合わせることで、ファイル操作からメール送信、Excel処理まで、幅広い業務を自動化できます。本記事では、すぐに実務で使えるスクリプト集を紹介します。

業務自動化の前に|環境準備と基本方針

必要なパッケージのインストール

# 仮想環境の作成
python3 -m venv .venv
source .venv/bin/activate

# 必要なパッケージのインストール
pip install openpyxl python-docx PyPDF2 python-dotenv schedule

自動化スクリプトの設計方針

  • 冪等性を確保する:スクリプトを複数回実行しても同じ結果になるよう設計する
  • ログを残す:処理の実行結果をログファイルに記録し、問題発生時に原因を追跡可能にする
  • エラーハンドリング:一部のファイルでエラーが発生しても、処理全体が停止しないようにする
  • 設定を外部化する:パス、メールアドレス、パスワードなどを環境変数や設定ファイルに分離する
# ログ設定の基本テンプレート
import logging
from datetime import datetime

log_file = f"automation_{datetime.now():%Y%m%d}.log"
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(message)s",
    handlers=[
        logging.FileHandler(log_file, encoding="utf-8"),
        logging.StreamHandler(),
    ],
)
logger = logging.getLogger(__name__)

ファイル操作の自動化

ファイルの整理・リネーム・移動は最も基本的な自動化対象です。

ファイルの一括リネーム

import os
from pathlib import Path
from datetime import datetime

def rename_files_with_date(directory: str, prefix: str = ""):
    """ディレクトリ内のファイルに日付プレフィックスを追加してリネームする"""
    dir_path = Path(directory)
    today = datetime.now().strftime("%Y%m%d")

    for file_path in dir_path.iterdir():
        if file_path.is_file() and not file_path.name.startswith(today):
            new_name = f"{today}_{prefix}{file_path.name}"
            new_path = file_path.parent / new_name
            file_path.rename(new_path)
            logger.info(f"リネーム: {file_path.name} → {new_name}")

# 実行
rename_files_with_date("./reports", prefix="report_")

ファイルの自動分類

from pathlib import Path
import shutil

def organize_files(source_dir: str):
    """拡張子ごとにファイルをフォルダに分類する"""
    source = Path(source_dir)
    extensions_map = {
        "画像": [".jpg", ".jpeg", ".png", ".gif", ".bmp", ".svg"],
        "文書": [".pdf", ".doc", ".docx", ".txt", ".xlsx", ".csv"],
        "動画": [".mp4", ".avi", ".mov", ".wmv"],
        "音声": [".mp3", ".wav", ".flac"],
        "アーカイブ": [".zip", ".tar", ".gz", ".rar"],
    }

    for file_path in source.iterdir():
        if not file_path.is_file():
            continue

        ext = file_path.suffix.lower()
        category = "その他"
        for cat, exts in extensions_map.items():
            if ext in exts:
                category = cat
                break

        dest_dir = source / category
        dest_dir.mkdir(exist_ok=True)
        shutil.move(str(file_path), str(dest_dir / file_path.name))
        logger.info(f"移動: {file_path.name} → {category}/")

# 実行
organize_files("./downloads")

古いファイルの自動削除

from pathlib import Path
from datetime import datetime, timedelta

def delete_old_files(directory: str, days: int = 30):
    """指定日数以上前のファイルを削除する"""
    dir_path = Path(directory)
    cutoff = datetime.now() - timedelta(days=days)
    deleted_count = 0

    for file_path in dir_path.rglob("*"):
        if file_path.is_file():
            modified_time = datetime.fromtimestamp(file_path.stat().st_mtime)
            if modified_time < cutoff:
                file_path.unlink()
                logger.info(f"削除: {file_path} (最終更新: {modified_time:%Y-%m-%d})")
                deleted_count += 1

    logger.info(f"合計 {deleted_count} 件のファイルを削除しました。")

# 30日以上前のログファイルを削除
delete_old_files("./logs", days=30)

Excel処理の自動化

openpyxlを使えば、ExcelファイルをPythonから自在に操作できます。

Excelファイルの読み込みとデータ抽出

import openpyxl

def read_excel_data(file_path: str, sheet_name: str = None):
    """Excelファイルからデータを読み込む"""
    wb = openpyxl.load_workbook(file_path, data_only=True)
    ws = wb[sheet_name] if sheet_name else wb.active

    # ヘッダー行の取得
    headers = [cell.value for cell in ws[1]]

    # データ行の取得
    data = []
    for row in ws.iter_rows(min_row=2, values_only=True):
        record = dict(zip(headers, row))
        data.append(record)

    wb.close()
    return data

# 実行
data = read_excel_data("sales_report.xlsx", "Sheet1")
for record in data[:5]:
    print(record)

Excelレポートの自動生成

import openpyxl
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
from openpyxl.chart import BarChart, Reference
from datetime import datetime

def create_monthly_report(data: list[dict], output_path: str):
    """月次レポートをExcelファイルとして生成する"""
    wb = openpyxl.Workbook()
    ws = wb.active
    ws.title = "月次レポート"

    # スタイル定義
    header_font = Font(bold=True, size=12, color="FFFFFF")
    header_fill = PatternFill(start_color="4472C4", end_color="4472C4", fill_type="solid")
    border = Border(
        left=Side(style="thin"),
        right=Side(style="thin"),
        top=Side(style="thin"),
        bottom=Side(style="thin"),
    )

    # タイトル
    ws.merge_cells("A1:E1")
    title_cell = ws["A1"]
    title_cell.value = f"月次売上レポート({datetime.now():%Y年%m月})"
    title_cell.font = Font(bold=True, size=16)

    # ヘッダー行
    headers = ["部門", "売上(万円)", "前月比(%)", "目標達成率(%)", "備考"]
    for col, header in enumerate(headers, 1):
        cell = ws.cell(row=3, column=col, value=header)
        cell.font = header_font
        cell.fill = header_fill
        cell.alignment = Alignment(horizontal="center")
        cell.border = border

    # データ行
    for row_idx, record in enumerate(data, 4):
        for col_idx, key in enumerate(headers, 1):
            cell = ws.cell(row=row_idx, column=col_idx, value=record.get(key, ""))
            cell.border = border
            if col_idx >= 2 and col_idx <= 4:
                cell.number_format = "#,##0"

    # 列幅の調整
    ws.column_dimensions["A"].width = 15
    ws.column_dimensions["B"].width = 18
    ws.column_dimensions["C"].width = 15
    ws.column_dimensions["D"].width = 18
    ws.column_dimensions["E"].width = 20

    # 棒グラフの追加
    chart = BarChart()
    chart.title = "部門別売上"
    chart.y_axis.title = "売上(万円)"
    data_ref = Reference(ws, min_col=2, min_row=3, max_row=3 + len(data))
    cats_ref = Reference(ws, min_col=1, min_row=4, max_row=3 + len(data))
    chart.add_data(data_ref, titles_from_data=True)
    chart.set_categories(cats_ref)
    chart.shape = 4
    ws.add_chart(chart, "A" + str(5 + len(data)))

    wb.save(output_path)
    logger.info(f"レポートを保存しました: {output_path}")

# サンプルデータ
sample_data = [
    {"部門": "営業1課", "売上(万円)": 1500, "前月比(%)": 105, "目標達成率(%)": 98, "備考": ""},
    {"部門": "営業2課", "売上(万円)": 1200, "前月比(%)": 98, "目標達成率(%)": 85, "備考": "人員減"},
    {"部門": "営業3課", "売上(万円)": 1800, "前月比(%)": 112, "目標達成率(%)": 110, "備考": "大型案件"},
]

create_monthly_report(sample_data, "monthly_report.xlsx")

複数Excelファイルの集約

import pandas as pd
from pathlib import Path

def merge_excel_files(directory: str, output_path: str):
    """ディレクトリ内の全Excelファイルを1つに集約する"""
    dir_path = Path(directory)
    all_data = []

    for excel_file in sorted(dir_path.glob("*.xlsx")):
        logger.info(f"読み込み: {excel_file.name}")
        df = pd.read_excel(excel_file)
        df["ファイル名"] = excel_file.stem
        all_data.append(df)

    if all_data:
        merged_df = pd.concat(all_data, ignore_index=True)
        merged_df.to_excel(output_path, index=False)
        logger.info(f"集約完了: {len(all_data)}ファイル → {output_path}")
    else:
        logger.warning("対象のExcelファイルが見つかりませんでした。")

merge_excel_files("./monthly_reports", "merged_report.xlsx")

メール送信の自動化

Pythonの標準ライブラリを使って、メールの自動送信を実装できます。

基本的なメール送信

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
import os
from dotenv import load_dotenv

load_dotenv()

def send_email(to_address: str, subject: str, body: str, attachments: list[str] = None):
    """メールを送信する"""
    smtp_server = os.getenv("SMTP_SERVER", "smtp.gmail.com")
    smtp_port = int(os.getenv("SMTP_PORT", "587"))
    from_address = os.getenv("EMAIL_ADDRESS")
    password = os.getenv("EMAIL_PASSWORD")

    msg = MIMEMultipart()
    msg["From"] = from_address
    msg["To"] = to_address
    msg["Subject"] = subject

    msg.attach(MIMEText(body, "plain", "utf-8"))

    # 添付ファイル
    if attachments:
        for file_path in attachments:
            with open(file_path, "rb") as f:
                part = MIMEBase("application", "octet-stream")
                part.set_payload(f.read())
            encoders.encode_base64(part)
            filename = os.path.basename(file_path)
            part.add_header("Content-Disposition", f"attachment; filename={filename}")
            msg.attach(part)

    with smtplib.SMTP(smtp_server, smtp_port) as server:
        server.starttls()
        server.login(from_address, password)
        server.send_message(msg)

    logger.info(f"メール送信完了: {to_address}")

# 環境変数ファイル(.env)
# EMAIL_ADDRESS=your-email@gmail.com
# EMAIL_PASSWORD=your-app-password
# SMTP_SERVER=smtp.gmail.com
# SMTP_PORT=587

一括メール送信(テンプレート使用)

import csv
from string import Template

def send_bulk_emails(csv_path: str, template_path: str, subject: str):
    """CSVの宛先リストに基づいてテンプレートメールを一括送信する"""
    # テンプレートの読み込み
    with open(template_path, "r", encoding="utf-8") as f:
        template = Template(f.read())

    # CSVの読み込みと送信
    with open(csv_path, "r", encoding="utf-8") as f:
        reader = csv.DictReader(f)
        for row in reader:
            body = template.substitute(
                name=row["名前"],
                company=row["会社名"],
                date=row["日付"],
            )
            try:
                send_email(row["メールアドレス"], subject, body)
            except Exception as e:
                logger.error(f"送信失敗 ({row['メールアドレス']}): {e}")

# テンプレートファイル(template.txt)
# ${name}様
#
# いつもお世話になっております。
# ${company}様の${date}の報告書を添付いたします。

PDF操作の自動化

PDFの結合

from PyPDF2 import PdfMerger
from pathlib import Path

def merge_pdfs(directory: str, output_path: str):
    """ディレクトリ内のPDFを1つに結合する"""
    merger = PdfMerger()
    dir_path = Path(directory)

    pdf_files = sorted(dir_path.glob("*.pdf"))
    if not pdf_files:
        logger.warning("PDFファイルが見つかりませんでした。")
        return

    for pdf_file in pdf_files:
        logger.info(f"追加: {pdf_file.name}")
        merger.append(str(pdf_file))

    merger.write(output_path)
    merger.close()
    logger.info(f"結合完了: {len(pdf_files)}ファイル → {output_path}")

merge_pdfs("./invoices", "merged_invoices.pdf")

PDFからテキストを抽出

from PyPDF2 import PdfReader

def extract_text_from_pdf(file_path: str) -> str:
    """PDFからテキストを抽出する"""
    reader = PdfReader(file_path)
    text = ""
    for page in reader.pages:
        text += page.extract_text() + "\n"
    return text

# 実行
text = extract_text_from_pdf("document.pdf")
print(text[:500])

定期実行の仕組み

自動化スクリプトを定期的に実行する方法を紹介します。

scheduleライブラリを使った方法

import schedule
import time

def daily_report_task():
    """日次レポート生成タスク"""
    logger.info("日次レポートの生成を開始します。")
    # ここに処理を記述
    logger.info("日次レポートの生成が完了しました。")

def weekly_cleanup_task():
    """週次クリーンアップタスク"""
    logger.info("クリーンアップを開始します。")
    delete_old_files("./logs", days=30)
    delete_old_files("./temp", days=7)

# スケジュール設定
schedule.every().day.at("09:00").do(daily_report_task)
schedule.every().monday.at("06:00").do(weekly_cleanup_task)

# 実行ループ
while True:
    schedule.run_pending()
    time.sleep(60)

cronを使った方法(Linux/macOS)

# crontabの編集
crontab -e

# 毎日9時にスクリプトを実行
0 9 * * * /path/to/.venv/bin/python /path/to/daily_report.py >> /path/to/cron.log 2>&1

# 毎週月曜6時にクリーンアップ
0 6 * * 1 /path/to/.venv/bin/python /path/to/cleanup.py >> /path/to/cron.log 2>&1

Windowsタスクスケジューラ

Windowsの場合は、タスクスケジューラを使ってスクリプトを定期実行できます。PowerShellから設定することも可能です。

# PowerShellでタスクを登録する例
$action = New-ScheduledTaskAction -Execute "C:\path\.venv\Scripts\python.exe" -Argument "C:\path\daily_report.py"
$trigger = New-ScheduledTaskTrigger -Daily -At "09:00"
Register-ScheduledTask -Action $action -Trigger $trigger -TaskName "DailyReport" -Description "日次レポート生成"

実践:業務自動化のスクリプト統合例

これまでのスクリプトを組み合わせた統合的な自動化の例を紹介します。

"""
日次業務自動化スクリプト
- 各部署のExcelレポートを集約
- 月次レポートを生成
- 関係者にメールで送信
"""
import logging
from datetime import datetime
from pathlib import Path

logger = logging.getLogger(__name__)


def main():
    today = datetime.now()
    logger.info(f"=== 日次自動化処理開始: {today:%Y-%m-%d %H:%M} ===")

    try:
        # 1. 各部署のExcelファイルを集約
        logger.info("Step 1: Excelファイルの集約")
        merge_excel_files("./daily_reports", f"./output/merged_{today:%Y%m%d}.xlsx")

        # 2. 古いファイルのクリーンアップ
        logger.info("Step 2: 古いファイルの削除")
        delete_old_files("./output", days=90)

        # 3. レポートをメールで送信
        logger.info("Step 3: メール送信")
        recipients = ["manager@example.com", "team-lead@example.com"]
        for recipient in recipients:
            send_email(
                to_address=recipient,
                subject=f"【自動送信】日次レポート {today:%Y/%m/%d}",
                body=f"{today:%Y年%m月%d日}の日次レポートを添付いたします。",
                attachments=[f"./output/merged_{today:%Y%m%d}.xlsx"],
            )

        logger.info("=== 日次自動化処理完了 ===")

    except Exception as e:
        logger.error(f"処理中にエラーが発生しました: {e}")
        # エラー通知メールの送信
        send_email(
            to_address="admin@example.com",
            subject="【エラー】日次自動化処理",
            body=f"エラー内容: {e}",
        )


if __name__ == "__main__":
    main()

まとめ

本記事では、Pythonを使った業務自動化の実践スクリプトを紹介しました。

  • ファイル操作:pathlibとshutilでリネーム・分類・削除を自動化
  • Excel処理:openpyxlとpandasでレポート生成・データ集約を実現
  • メール送信:smtplibで添付ファイル付きメールの一括送信が可能
  • PDF操作:PyPDF2でPDFの結合やテキスト抽出を自動化
  • 定期実行:scheduleライブラリやcronで自動スケジューリング

業務自動化は、まず小さなスクリプトから始めることが重要です。毎日5分かかる作業を自動化するだけでも、年間で約20時間の工数削減になります。本記事のスクリプトをベースに、自社の業務に合わせたカスタマイズを行ってみてください。

#Python#自動化#業務効率化
共有:
無料メルマガ

週1回、最新の技術記事をお届け

AI・クラウド・開発の最新記事を毎週月曜にメールでお届けします。登録は無料、いつでも解除できます。

プライバシーポリシーに基づき管理します

起業準備に役立つ情報、もっとありますよ。

まずは話だけ聞いてもらう