🤖

【業務効率化】Pythonを使った勤怠表自動転記ツールの作り方

2025/02/11に公開

Pythonのインストール

  1. 公式サイト から最新のPythonをダウンロード
  2. インストーラーを実行し、「Add Python to PATH」にチェックを入れる
  3. インストール完了後、ターミナル(またはコマンドプロンプト)で以下を実行して確認
    python --version
    
    正しくバージョンが表示されればOK

VS Codeのインストール(まだの場合)

Python拡張機能のインストール

  1. VS Codeを開く
  2. 拡張機能(Ctrl + Shift + X) を開く
  3. 「Python」を検索し、MicrosoftのPython拡張機能をインストール

仮想環境の作成(推奨)

プロジェクトごとにパッケージ管理を分けたい場合、仮想環境を作ると便利です。

  1. VS Codeのターミナルを開く(Ctrl + `)
  2. 以下のコマンドを実行
    python -m venv venv
    
  3. 仮想環境を有効化(Windows)
    venv\Scripts\activate
    
    Macの場合:
    source venv/bin/activate
    
  4. ターミナルに (venv) が表示されたら成功

必要なライブラリをインストール

このプロジェクトで使う pandasopenpyxl をインストール

pip install pandas openpyxl

以下のディレクトリ構造でファイルを作成する

kintai_tool/
│── main.py               # メインスクリプト(実行ファイル)
│── gui.py                # GUIでmain.pyを実行するため
│── config.py             # 設定ファイル(従業員名などの設定管理)
│── utils.py              # 補助関数(Excel操作・データ処理)
│── templates/            # ひな型フォルダ
│   └── 勤怠表雛形.xlsx    # 勤怠表のテンプレートファイル
│── input/                # 入力ファイル(CSVの格納場所)
│   ├── 勤怠詳細_YYYYMM_〇〇.csv  # ダウンロードしたCSVデータ
│── output/               # 出力ファイル(生成されたExcelの格納場所)
│   ├── 勤怠表_YYYYMM_〇〇.xlsx   # 生成されたExcelファイル
│── logs/                 # ログファイル(エラー管理用)
│── requirements.txt       # 必要なPythonライブラリ
│── README.md              # 使い方の説明
エクスプローラーで見るとこのようになります。

VScodeで見るとこのようになります。

main.py、config.py、utils.py、gui.py をそれぞれ作成する

main.py
import os
import argparse
import pandas as pd
from datetime import datetime
from utils import read_csv, process_data, write_to_excel
from config import DEFAULT_EMPLOYEE_NAME, INPUT_DIR, OUTPUT_DIR

# 必要なフォルダが存在しない場合は作成
os.makedirs(INPUT_DIR, exist_ok=True)
os.makedirs(OUTPUT_DIR, exist_ok=True)

# コマンドライン引数の処理
parser = argparse.ArgumentParser(description="勤怠データをExcelに変換するツール")
parser.add_argument("--name", type=str, default=DEFAULT_EMPLOYEE_NAME, help="従業員名を指定")
parser.add_argument("--file", type=str, required=True, help="処理するCSVファイルのパス")
parser.add_argument("--template", type=str, required=True, help="テンプレートExcelファイルのパス")
args = parser.parse_args()

# CSVデータを読み込み
df = read_csv(args.file)

# CSVから月情報を取得
first_date = df["日付"].min()
year_month = first_date.to_pydatetime().strftime("%Y%m")

# データの整形
df_processed = process_data(df)

# 出力ファイル名を作成
output_filename = f"勤怠表_{year_month}_{args.name}.xlsx"
output_path = os.path.join(OUTPUT_DIR, output_filename)

# Excelに書き込み(不足していた csv_filename を追加)
write_to_excel(args.template, output_path, df_processed, args.file)  

print(f"✅ 勤怠表を作成しました: {output_path}")

config.py
import os
import sys
import configparser
from pathlib import Path

def get_config_path():
    """実行ファイルと同じディレクトリのconfig.iniのパスを返す"""
    if getattr(sys, 'frozen', False):
        # exe実行時
        base_path = Path(sys.executable).parent
    else:
        # 通常実行時
        base_path = Path(__file__).parent
    return base_path / 'config.ini'

def create_default_config():
    """デフォルトの設定ファイルを作成する"""
    config = configparser.ConfigParser(interpolation=None)  # 補間を無効化
    
    # デフォルト設定
    config['DEFAULT'] = {
        'employee_name': '小島知将',
        'template_path': 'templates/勤怠表雛形_2025年版.xlsx'
    }
    
    config['PATHS'] = {
        'input_dir': 'input',
        'output_dir': 'output'
    }
    
    config['CSV'] = {
        'encoding': 'utf-8',
        'date_format': '%Y-%m-%d'
    }
    
    # 設定ファイルを保存
    with open(get_config_path(), 'w', encoding='utf-8') as f:
        config.write(f)

def load_config():
    """設定を読み込む。ない場合は作成する"""
    config = configparser.ConfigParser(interpolation=None)  # 補間を無効化
    config_path = get_config_path()
    
    # config.iniが存在しない場合、デフォルト設定で作成
    if not config_path.exists():
        create_default_config()
    
    config.read(config_path, encoding='utf-8')
    return config

def save_config(config):
    """設定を保存する"""
    with open(get_config_path(), 'w', encoding='utf-8') as f:
        config.write(f)

def get_default_employee_name():
    return load_config()['DEFAULT']['employee_name']

def get_template_path():
    return load_config()['DEFAULT']['template_path']

def get_input_dir():
    return load_config()['PATHS']['input_dir']

def get_output_dir():
    return load_config()['PATHS']['output_dir']

def get_csv_encoding():
    return load_config()['CSV']['encoding']

def get_date_format():
    return load_config()['CSV']['date_format']

def update_config(name, template):
    """config.iniに氏名とテンプレートファイルのパスを保存"""
    config = load_config()
    config['DEFAULT']['employee_name'] = name
    config['DEFAULT']['template_path'] = template
    save_config(config)

def ensure_directories():
    """必要なディレクトリを作成"""
    dirs = ['input', 'output', 'templates']
    for dir_name in dirs:
        os.makedirs(dir_name, exist_ok=True)

# プログラム起動時に実行
ensure_directories()
utils.py
import os
import pandas as pd
import openpyxl
from openpyxl.utils import get_column_letter
from config import get_csv_encoding, get_date_format

def read_csv(csv_path):
    """
    CSVファイルを読み込み、DataFrameとして返す
    """
    df = pd.read_csv(csv_path, encoding=get_csv_encoding())
    df["日付"] = pd.to_datetime(df["日付"], format=get_date_format())
    return df

def process_data(df):
    """
    勤怠データを整形する
    """
    # 必要なカラムの選択
    columns_to_keep = ["日付", "始業時刻", "終業時刻", "総勤務時間", "法定内残業", "時間外労働", "深夜労働", "勤怠種別"]
    df_filtered = df[columns_to_keep].copy()
    
    # 不要データの削除(未入力、休日)
    # 未入力・休日データも残すように変更
    # df_filtered = df_filtered[~df_filtered["勤怠種別"].isin(["未入力", "所定休日", "法定休日"])]
    
    # 時間を小数時間に変換
    def time_to_hours(time_str):
        if isinstance(time_str, str) and ":" in time_str:
            h, m = map(int, time_str.split(":"))
            return h + m / 60  # 分を時間に変換
        return 0

    df_filtered["総勤務時間"] = df_filtered["総勤務時間"].apply(time_to_hours)
    
    return df_filtered

def write_to_excel(template_path, output_path, df, csv_filename):
    """
    ひな型Excelに勤怠データを書き込む
    """
    import openpyxl
    wb = openpyxl.load_workbook(template_path)
    sheet = wb["勤務表"]

    # G1セルにCSVファイル名から取得した従業員名を記載
    import re
    name_match = re.search(r'勤怠詳細_(.+?)_\d{4}_\d{2}', os.path.basename(csv_filename))
    employee_name = name_match.group(1) if name_match else "不明"
    sheet["G1"] = employee_name

    # H5セルの月を取得し、それに基づいてA列の日付を設定
    month_value = df["日付"].dt.month.iloc[0]
    year_value = df["日付"].dt.year.iloc[0]
    sheet["H5"] = month_value
    sheet["F5"] = year_value

    for index, row in enumerate(df.itertuples(), start=11):  # C列から開始
        day_value = index - 10  # A11に1日から入力
        sheet[f"A{index}"] = f"=DATE({year_value},{month_value},{day_value})"
        sheet[f"C{index}"] = row.始業時刻
        sheet[f"D{index}"] = row.終業時刻
        sheet[f"E{index}"] = "1:00" if row.勤怠種別 not in ["未入力", "所定休日", "法定休日"] else ""  # 休憩時間
        sheet[f"F{index}"] = row.総勤務時間  

    wb.save(output_path)
    print(f"✅ Excelファイルを保存しました: {output_path}")
gui.py
import os
import tkinter as tk
from tkinter import filedialog, messagebox
import subprocess
from config import INPUT_DIR, TEMPLATE_PATH, DEFAULT_EMPLOYEE_NAME, update_config  # config.ini ではなく config.py から取得

def select_csv():
    """CSVファイルを選択する"""
    file_path = filedialog.askopenfilename(initialdir=INPUT_DIR, title="CSVファイルを選択", filetypes=[("CSV files", "*.csv")])
    if file_path:
        csv_entry.delete(0, tk.END)
        csv_entry.insert(0, file_path)

def select_template():
    """テンプレートファイルを選択する"""
    file_path = filedialog.askopenfilename(initialdir=os.path.dirname(TEMPLATE_PATH), title="テンプレートファイルを選択", filetypes=[("Excel files", "*.xlsx")])
    if file_path:
        template_entry.delete(0, tk.END)
        template_entry.insert(0, file_path)

def open_output_folder():
    """出力フォルダを開く"""
    output_dir = os.path.abspath("output")
    if os.path.exists(output_dir):
        os.startfile(output_dir)  # Windows
    else:
        messagebox.showerror("エラー", "出力フォルダが見つかりません。")

def run_main():
    csv_file = csv_entry.get()
    template_file = template_entry.get()
    employee_name = name_entry.get().strip()
    
    if not csv_file:
        messagebox.showerror("エラー", "CSVファイルを選択してください。")
        return
    
    if not template_file:
        messagebox.showerror("エラー", "テンプレートファイルを選択してください。")
        return
    
    if not employee_name:
        messagebox.showerror("エラー", "氏名を入力してください。")
        return
    
    # config.py を更新
    update_config(employee_name, template_file)
    
    try:
        subprocess.run(["python", "main.py", "--name", employee_name, "--file", csv_file, "--template", template_file], check=True)
        messagebox.showinfo("完了", "勤怠表の作成が完了しました!")
        open_output_folder()
    except subprocess.CalledProcessError:
        messagebox.showerror("エラー", "処理中にエラーが発生しました。")

# GUIウィンドウの作成
root = tk.Tk()
root.title("勤怠表作成ツール")
root.geometry("500x400")
root.configure(bg="#f5f5f5")

font_style = ("Arial", 12)
button_style = {"font": font_style, "bg": "#4CAF50", "fg": "white", "activebackground": "#45a049", "padx": 10, "pady": 5}

tk.Label(root, text="CSVファイル:", font=font_style, bg="#f5f5f5").pack(pady=(10, 0))
csv_entry = tk.Entry(root, width=50, font=font_style)
csv_entry.pack()
tk.Button(root, text="参照", command=select_csv, **button_style).pack(pady=5)

tk.Label(root, text="テンプレートファイル:", font=font_style, bg="#f5f5f5").pack(pady=(10, 0))
template_entry = tk.Entry(root, width=50, font=font_style)
template_entry.insert(0, TEMPLATE_PATH)  # config.py から取得
template_entry.pack()
tk.Button(root, text="参照", command=select_template, **button_style).pack(pady=5)

tk.Label(root, text="氏名:", font=font_style, bg="#f5f5f5").pack(pady=(10, 0))
name_entry = tk.Entry(root, width=50, font=font_style)
name_entry.insert(0, DEFAULT_EMPLOYEE_NAME)  # config.py から取得
name_entry.pack()

tk.Button(root, text="実行", command=run_main, **button_style).pack(pady=15)

root.mainloop()

動作テストを実行する

1️⃣ 必要なフォルダの作成

以下のコマンドを実行して、フォルダを作成してください。
※すでに作成済であれば不要

mkdir -p input output templates logs

2️⃣ templates/ に雛形を配置

  • 勤怠表雛形_yyyy年版.xlsxtemplates/ に移動

3️⃣ input/ にテスト用CSVを配置

  • freeeからダウンロードしたCSVを input/ に配置(例:勤怠詳細_202502_氏名.csv

4️⃣ gui.py を実行

  • 以下のように、GUIが起動するか確認

5️⃣ 「参照」からinput/に配置したcsvファイルを選択する

6️⃣ 「実行」をクリックして、出力されたExcelを確認

  • 自動で開くoutputフォルダから(例)勤怠表_202502_氏名.xlsx を開いて、データが正しく記入されているかチェック

「gui.py」を.exeファイルに変換する

1️⃣ pyinstaller のインストール

pip install pyinstallerコマンドプロンプト (Windows) または ターミナル (Mac/Linux) で実行します。

  1. kintai_tool/ ディレクトリに移動

    (例)dev/内にkintai_toolフォルダがある場合
    cd C:\Users\my-pc\dev\kintai_tool
    
  2. pyinstaller をインストール

    pip install pyinstaller
    

2️⃣ .exe を作成

次に、以下のコマンドを実行し、exe ファイルを作成します。

pyinstaller --onefile --windowed --name "勤怠表自動作成ツールver.1.0" gui.py

🔹 オプションの意味

  • --onefile.exe1つのファイルにまとめる
  • --windowedGUIアプリとして実行tkinter 用)
  • --name "勤怠表自動作成ツールver.1.0"出力する .exe の名前を指定

3️⃣ .exe の保存場所を確認

コマンド実行後、以下のようなディレクトリが作成されます。

kintai_tool/
│── dist/
│   ├── 勤怠表自動作成ツールver.1.0.exe  # ここに実行ファイルが作成される
│── build/  # ビルド時に作成される一時フォルダ(削除可)
│── gui.spec  # PyInstaller の設定ファイル
│── gui.py
│── main.py
│── config.py
│── utils.py
│── templates/
│── input/
│── output/
│── logs/
│── README.md

4️⃣ .exe の動作確認

  1. dist/ フォルダに移動
  2. 勤怠表自動作成ツールver.1.0.exe をダブルクリック
  3. GUI が正しく開くか確認
  4. 実行 ボタンを押して 勤怠表が正常に作成されるかチェック
  5. output フォルダが 自動で開くか確認

5️⃣ 不要なファイル・フォルダの削除

.exe 作成後、以下のファイル・フォルダは 削除しても問題ありません

rm -r build/
rm gui.spec

✅ Python をインストールしていない環境で実行できるか?

pyinstaller で作成した .exePython 環境がないPCでも実行可能
.exe必要な Python ライブラリがすべて含まれる
.exe をそのまま配布するだけでOK 🎉


GitHubリポジトリを作成し、ローカルリポジトリと連携する

  1. GitHubで新しいリポジトリを作成
  • GitHubにログインし、「New Repository」ボタンをクリック。
  • Description: 「勤怠表自動作成ツール」など
  • Private/Public を選択
  • リポジトリ名を kintai_tool に設定し、「Create repository」をクリック。
  1. ローカルリポジトリを作成または移動
cd C:\Users\my-pc\dev\kintai_tool
git init
  1. .gitignore ファイルの作成:
# PowerShellの場合
New-Item -Path .gitignore -ItemType File

# または、メモ帳等で.gitignoreファイルを作成
  1. .gitignore の内容:
gitignore
# Python
__pycache__/
*.py[cod]
*$py.class
.Python
build/
dist/
*.egg-info/

# PyInstaller
*.manifest
*.spec

# Folders
input/*
output/*
!input/.gitkeep
!output/.gitkeep

# Config
config.ini

# Logs
*.log

# IDE
.idea/
.vscode/
*.swp

# Virtual Environment
venv/
env/
  1. .gitkeep ファイルの作成 (空のフォルダを維持するため):
# PowerShellの場合
New-Item -Path "input\.gitkeep" -ItemType File
New-Item -Path "output\.gitkeep" -ItemType File
  1. .gitattributes の作成:
# PowerShellの場合
New-Item -Path .gitattributes -ItemType File
  1. GitHubリポジトリとローカルリポジトリを接続

git remote add origin https://github.com/your-username/kintai_tool.git
  1. ファイルをステージングしてコミット
git add .
git commit -m "勤怠表自動作成ツール v1.0 初回コミット"
  1. リポジトリにpush
git branch -M main
git push -u origin main

GitHubのReleasesセクションで配布用ZIPを提供する

  1. GitHubのリポジトリを開く

    • GitHubにログインし、リポジトリ(kintai_tool)を開く。
  2. 新しいリリースを作成

    • 「Releases」タブを開く。

  • 「Create a new release」をクリック。
  1. リリース情報を入力
    • Tag versionv1.0 と入力。

  • Release title勤怠表自動作成ツール v1.0 と入力。

  • Description にバージョンの変更点や説明を記入。

  1. ZIPファイルをアップロード

    • 勤怠表自動作成ツール_v1.0.zip をドラッグ&ドロップ。
  2. リリースを公開

    • 「Publish release」ボタンを押して完了。

Discussion