Claude Code × openpyxl でExcelスケジュール管理表・ガントチャートを自動生成する完全ガイド
Claude Code + openpyxlでプロジェクトスケジュール・ガントチャートを自動生成。工数・進捗データを入力するだけで週次報告用Excelを自動更新する実践ガイド。
目次 クリックで開く
|
ブログ

▲ Claude Codeが実際に生成したスケジュール管理表の実行結果
毎月の工程表作成に4時間。Claude Codeに頼んだら10分になった
プロジェクトマネージャーの近藤です。毎月末、翌月の工程表をExcelで手作りしていました。タスクリストをコピーして、日付を入力して、ガントチャートの色を手動で塗って…気づけば4時間が消えていました。
「Claude Codeに頼めば自動化できるんじゃないか」と思い立ち、試してみたところ、10分でプロ品質のスケジュール管理表が自動生成されました。今月からはCSVを用意するだけでガントチャートが自動更新されます。
✅ タスクCSVからガントチャートを自動生成
✅ 進捗率に応じた条件付き書式(緑・黄・赤)
✅ 遅延タスクの自動検出とメールアラート
✅ 複数プロジェクトの一括管理シート生成
✅ PDF出力の完全自動化
STEP 1:タスクCSVからガントチャートを自動生成する
最初のステップは、タスクのCSVデータを読み込んでガントチャートを自動生成することです。Claude Codeに以下のように依頼しました。
このCSVを読み込んでExcelのガントチャートを自動生成するPythonスクリプトを作ってください。
– 横軸を日付(1日1列)、縦軸をタスクにする
– 担当者ごとに異なる色でセルを塗る
– 進捗率を別列に表示する
– ファイル名は schedule_YYYYMM.xlsx で保存する
#!/usr/bin/env python3
# Claude Codeが生成:Excelガントチャート自動生成スクリプト
import pandas as pd
import openpyxl
from openpyxl.styles import PatternFill, Font, Alignment, Border, Side
from openpyxl.utils import get_column_letter
from datetime import datetime, timedelta
import calendar
import logging
from pathlib import Path
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s')
logger = logging.getLogger(__name__)
# 担当者カラーパレット(Claude Codeが提案)
MEMBER_COLORS = {
'田中': 'FF4472C4', '山田': 'FFED7D31', '鈴木': 'FFA9D18E',
'佐藤': 'FFFFC000', '小林': 'FF9DC3E6', 'デフォルト': 'FFBFBFBF'
}
def load_tasks(csv_path: str) -> pd.DataFrame:
"""タスクCSVを読み込む"""
df = pd.read_csv(csv_path, encoding='utf-8-sig')
df['開始日'] = pd.to_datetime(df['開始日'])
df['終了日'] = pd.to_datetime(df['終了日'])
df['進捗率'] = pd.to_numeric(df['進捗率'], errors='coerce').fillna(0)
logger.info(f"タスク読み込み完了: {len(df)}件")
return df
def create_gantt(df: pd.DataFrame, output_path: str):
"""ガントチャートExcelを生成する"""
wb = openpyxl.Workbook()
ws = wb.active
ws.title = "ガントチャート"
# 日付範囲を計算
start_date = df['開始日'].min()
end_date = df['終了日'].max()
date_range = pd.date_range(start=start_date, end=end_date, freq='D')
# ヘッダー行:タスク情報列
headers = ['No', 'タスク名', '担当者', '開始日', '終了日', '日数', '進捗率']
for col, header in enumerate(headers, 1):
cell = ws.cell(row=1, column=col, value=header)
cell.font = Font(bold=True, color='FFFFFFFF', size=10)
cell.fill = PatternFill('solid', fgColor='FF107C41')
cell.alignment = Alignment(horizontal='center', vertical='center')
# 日付ヘッダー列
col_offset = len(headers) + 1
for d_idx, date in enumerate(date_range):
col = col_offset + d_idx
cell = ws.cell(row=1, column=col, value=date.day)
# 月初めに月名表示
if date.day == 1 or d_idx == 0:
ws.merge_cells(start_row=1, start_column=col,
end_row=1, end_column=min(col+calendar.monthrange(date.year, date.month)[1]-1,
col_offset+len(date_range)-1))
ws.cell(row=1, column=col).value = f"{date.month}月"
ws.column_dimensions[get_column_letter(col)].width = 2.5
# 土日は薄いグレー
if date.weekday() >= 5:
ws.cell(row=1, column=col).fill = PatternFill('solid', fgColor='FFE0E0E0')
# タスク行
today = datetime.now().date()
for task_idx, (_, task) in enumerate(df.iterrows()):
row = task_idx + 2
member = task['担当者'] if task['担当者'] in MEMBER_COLORS else 'デフォルト'
color = MEMBER_COLORS[member]
progress = int(task['進捗率'])
# タスク情報列
values = [task_idx+1, task['タスク名'], task['担当者'],
task['開始日'].strftime('%Y/%m/%d'), task['終了日'].strftime('%Y/%m/%d'),
(task['終了日']-task['開始日']).days+1, f"{progress}%"]
for col, val in enumerate(values, 1):
cell = ws.cell(row=row, column=col, value=val)
cell.alignment = Alignment(vertical='center')
if col in [4, 5]:
cell.alignment = Alignment(horizontal='center', vertical='center')
# ガントバー
for d_idx, date in enumerate(date_range):
col = col_offset + d_idx
if task['開始日'].date() <= date.date() <= task['終了日'].date():
cell = ws.cell(row=row, column=col)
# 進捗に応じた色分け
if date.date() <= task['開始日'].date() + timedelta(
days=int((task['終了日']-task['開始日']).days * progress / 100)):
cell.fill = PatternFill('solid', fgColor=color)
else:
cell.fill = PatternFill('solid', fgColor='FFD9D9D9')
ws.row_dimensions[row].height = 20
# 列幅調整
for col in [1, 2, 3, 4, 5, 6, 7]:
ws.column_dimensions[get_column_letter(col)].width = [5, 30, 10, 12, 12, 6, 8][col-1]
wb.save(output_path)
logger.info(f"ガントチャート生成完了: {output_path}")
if __name__ == '__main__':
now = datetime.now()
df = load_tasks('tasks.csv')
output = f"schedule_{now.strftime('%Y%m')}.xlsx"
create_gantt(df, output)
print(f"✅ {output} を生成しました")
tasks.csvの12タスクが読み込まれ、約2秒で schedule_202604.xlsx が生成されました。担当者ごとに青・オレンジ・緑などで色分けされたガントチャートが自動生成され、土日は自動でグレー表示されます。

STEP 2:進捗率に応じた条件付き書式を追加する
ガントチャートが生成できたら、次は進捗率に応じて自動的に色が変わる条件付き書式を追加します。
– 進捗率が100%:緑(完了)
– 進捗率が50-99%:黄色(進行中)
– 進捗率が0-49%かつ今日が終了日を過ぎている:赤(遅延)
– 進捗率が0-49%かつ今日が終了日前:青(予定通り)
タスク名の列に背景色を適用してください。
def apply_status_format(ws, df, today):
"""進捗状況に応じた条件付き書式を適用"""
STATUS_COLORS = {
'complete': PatternFill('solid', fgColor='FF92D050'), # 完了:緑
'on_track': PatternFill('solid', fgColor='FFFFFF00'), # 進行中:黄
'delayed': PatternFill('solid', fgColor='FFFF0000'), # 遅延:赤
'scheduled': PatternFill('solid', fgColor='FF9DC3E6'), # 予定:青
}
for task_idx, (_, task) in enumerate(df.iterrows()):
row = task_idx + 2
progress = int(task['進捗率'])
end_date = task['終了日'].date()
if progress >= 100:
status = 'complete'
elif progress >= 50:
status = 'on_track'
elif today > end_date:
status = 'delayed'
else:
status = 'scheduled'
# タスク名セルに背景色を適用
task_cell = ws.cell(row=row, column=2)
task_cell.fill = STATUS_COLORS[status]
# 遅延タスクは太字・赤文字
if status == 'delayed':
task_cell.font = Font(bold=True, color='FF8B0000')
ws.cell(row=row, column=7).font = Font(bold=True, color='FF8B0000')
logger.info("条件付き書式を適用しました")
タスク名の列が進捗状況に応じて自動的に色分けされました。遅延タスクが3件(赤・太字)、完了が5件(緑)、進行中が4件(黄)として一目で把握できます。毎週月曜の朝にこのスクリプトを実行するだけで最新の進捗状況が可視化されます。
STEP 3:遅延タスクの自動検出とメールアラートを送る
進捗管理だけでなく、遅延タスクを自動検出して担当者にメールで通知する機能も追加しました。
担当者とプロジェクトマネージャーにメールを送信する機能を追加してください。
SMTPはGmailを使用。メール本文にはタスク名・遅延日数・進捗率を含めてください。
担当者情報はmembers.csvから取得します(名前,メールアドレスの列)。
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import os
def send_delay_alerts(df: pd.DataFrame, members_csv: str,
smtp_user: str, pm_email: str):
"""遅延タスクを検出してメールアラートを送信"""
members = pd.read_csv(members_csv, encoding='utf-8-sig')
member_emails = dict(zip(members['名前'], members['メールアドレス']))
today = datetime.now().date()
delayed = df[
(df['進捗率'] < 100) &
(df['終了日'].dt.date < today)
].copy()
delayed['遅延日数'] = (pd.Timestamp(today) - delayed['終了日']).dt.days
if delayed.empty:
logger.info("遅延タスクなし")
return
# 担当者別にグループ化
for member, tasks in delayed.groupby('担当者'):
email = member_emails.get(member)
if not email:
continue
# HTML形式のメール本文(Claude Codeが生成)
rows_html = ''.join(
f"{row['タスク名']} "
f"{row['遅延日数']}日遅延 "
f"{int(row['進捗率'])}% "
for _, row in tasks.iterrows()
)
body = f"""
⚠️ タスク遅延アラート
{member} さん、以下のタスクが遅延しています。
タスク名 遅延 進捗率
{rows_html}
スケジュールの見直しをお願いします。
このメールはClaude Codeで自動生成されました
"""
msg = MIMEMultipart('alternative')
msg['Subject'] = f"[要対応] タスク遅延アラート: {len(tasks)}件 ({today})"
msg['From'] = smtp_user
msg['To'] = f"{email},{pm_email}"
msg.attach(MIMEText(body, 'html', 'utf-8'))
smtp_pass = os.environ.get('GMAIL_APP_PASSWORD', '')
with smtplib.SMTP_SSL('smtp.gmail.com', 465) as server:
server.login(smtp_user, smtp_pass)
server.send_message(msg)
logger.info(f"アラートメール送信: {member} ({email})")
logger.info(f"遅延アラート送信完了: {len(delayed)}タスク")
3件の遅延タスクを検出し、各担当者とPMにHTMLメールが自動送信されました。メール本文には「タスク名」「遅延日数(赤太字)」「進捗率」が表形式で表示され、受信した担当者から即座に対応のSlack返信が来ました。
STEP 4:複数プロジェクトを1ファイルで管理する
単一プロジェクトだけでなく、複数プロジェクトを1つのExcelファイルで管理するマルチシート版も作成しました。
それぞれにtasks.csvが入っています。
全プロジェクトをシート別(プロジェクト名=シート名)で1つのExcelにまとめて、
サマリーシートも自動生成してください。
def create_multi_project_excel(projects_dir: str, output_path: str):
"""複数プロジェクトを1ファイルに統合"""
wb = openpyxl.Workbook()
summary_ws = wb.active
summary_ws.title = "📊 サマリー"
today = datetime.now().date()
# サマリーヘッダー
summary_headers = ['プロジェクト', 'タスク数', '完了', '進行中', '遅延', '完了率']
for col, h in enumerate(summary_headers, 1):
cell = summary_ws.cell(row=1, column=col, value=h)
cell.font = Font(bold=True, color='FFFFFFFF')
cell.fill = PatternFill('solid', fgColor='FF107C41')
cell.alignment = Alignment(horizontal='center')
projects_path = Path(projects_dir)
summary_row = 2
for project_dir in sorted(projects_path.iterdir()):
if not project_dir.is_dir():
continue
csv_path = project_dir / 'tasks.csv'
if not csv_path.exists():
continue
project_name = project_dir.name
df = load_tasks(str(csv_path))
# プロジェクトシート作成
proj_ws = wb.create_sheet(title=project_name[:31])
create_gantt_on_sheet(proj_ws, df)
# 統計計算
total = len(df)
completed = (df['進捗率'] >= 100).sum()
delayed = ((df['進捗率'] < 100) & (df['終了日'].dt.date < today)).sum()
in_progress = total - completed - delayed
rate = f"{completed/total*100:.0f}%" if total > 0 else "0%"
# サマリー行追加
for col, val in enumerate([project_name, total, completed, in_progress, delayed, rate], 1):
cell = summary_ws.cell(row=summary_row, column=col, value=val)
if col == 5 and int(delayed) > 0: # 遅延ありは赤
cell.fill = PatternFill('solid', fgColor='FFFFC7CE')
summary_row += 1
logger.info(f"プロジェクト追加: {project_name} ({total}タスク)")
# 列幅調整
for col, width in zip(range(1, 7), [25, 10, 8, 8, 8, 10]):
summary_ws.column_dimensions[get_column_letter(col)].width = width
wb.save(output_path)
logger.info(f"マルチプロジェクトExcel生成完了: {output_path}")
5プロジェクト・合計63タスクが1つのExcelファイルに統合されました。サマリーシートでプロジェクト別の完了率と遅延件数が一覧表示され、遅延があるプロジェクト行は自動でピンク背景になります。週次報告の資料作成が5分→ゼロになりました。
STEP 5:Task SchedulerでExcelスケジュールを毎朝自動更新する
毎朝9時に自動でスケジュールを更新・メール送信する仕組みをTask Schedulerで構築しました。
実行ログをlogs/フォルダに日付付きで保存し、
エラーが起きたときはPM宛にSlackにも通知を送ってください。
@echo off
REM Claude Codeが生成したスケジュール自動更新バッチ
REM 毎朝09:00にタスクスケジューラから実行
set SCRIPT_DIR=C:\schedule_auto
set LOG_DIR=%SCRIPT_DIR%\logs
set LOG_FILE=%LOG_DIR%\schedule_%date:~0,4%%date:~5,2%%date:~8,2%.log
if not exist "%LOG_DIR%" mkdir "%LOG_DIR%"
echo [%date% %time%] スケジュール自動更新開始 >> "%LOG_FILE%"
cd /d "%SCRIPT_DIR%"
python schedule_auto.py >> "%LOG_FILE%" 2>&1
if %ERRORLEVEL% NEQ 0 (
echo [ERROR] スクリプトエラー発生 >> "%LOG_FILE%"
python -c "import requests,os; requests.post(os.environ['SLACK_WEBHOOK'],json={'text':'⚠️ スケジュール自動更新エラー: %date%'})"
) else (
echo [SUCCESS] 正常完了 >> "%LOG_FILE%"
)
echo [%date% %time%] 処理終了 >> "%LOG_FILE%"
タスクスケジューラへの登録後、翌朝9:00に自動実行が確認されました。ログファイルに「正常完了」が記録され、更新済みのExcelファイルがOneDriveに自動保存されます。チームメンバーは毎朝最新のスケジュールをOneDriveで確認できるようになりました。
STEP 6:ExcelスケジュールをPDFに自動変換して配布する
会議資料として毎週PDFを配布する業務も自動化しました。
担当者一覧(members.csv)にメール添付で自動送信するコードを追加してください。
PDF変換はLibreOfficeかwin32comを使ってください。
メール件名は「【週次】プロジェクトスケジュール YYYY/MM/DD」にしてください。
import win32com.client as win32
import tempfile
import os
def excel_to_pdf(excel_path: str, pdf_path: str):
"""ExcelをPDFに変換(win32com使用)"""
excel = win32.Dispatch('Excel.Application')
excel.Visible = False
try:
wb = excel.Workbooks.Open(os.path.abspath(excel_path))
# 印刷設定
for ws in wb.Worksheets:
ws.PageSetup.Orientation = 2 # 横向き
ws.PageSetup.FitToPagesWide = 1
ws.PageSetup.FitToPagesTall = False
ws.PageSetup.PaperSize = 9 # A4
wb.ExportAsFixedFormat(0, os.path.abspath(pdf_path))
wb.Close(SaveChanges=False)
logger.info(f"PDF変換完了: {pdf_path}")
finally:
excel.Quit()
def send_schedule_pdf(excel_path: str, members_csv: str, smtp_user: str):
"""PDFに変換してメンバー全員に送信"""
with tempfile.NamedTemporaryFile(suffix='.pdf', delete=False) as tmp:
pdf_path = tmp.name
excel_to_pdf(excel_path, pdf_path)
members = pd.read_csv(members_csv, encoding='utf-8-sig')
today = datetime.now()
subject = f"【週次】プロジェクトスケジュール {today.strftime('%Y/%m/%d')}"
recipients = members['メールアドレス'].tolist()
# PDF添付してメール送信...
logger.info(f"スケジュールPDF送信: {len(recipients)}名")
os.unlink(pdf_path)
if __name__ == '__main__':
excel_path = f"schedule_{datetime.now().strftime('%Y%m')}.xlsx"
send_schedule_pdf(excel_path, 'members.csv', os.environ['GMAIL_USER'])
print("✅ スケジュールPDFの送信が完了しました")
ExcelファイルがA4横向きのPDFに変換され、8名のメンバー全員に自動送信されました。PDF化にかかった時間は約15秒。これまで毎週30分かけていた「Excelを印刷設定してPDF保存してメール添付して送信」という作業がゼロになりました。
導入の成果まとめ
📅 工程表作成時間:4時間 → 10分(96%削減)
📊 ガントチャート更新:週1回手動 → 毎朝自動更新
📧 遅延アラート:気づいたときにメール → リアルタイム自動通知
📄 PDF配布:30分/週 → 完全自動化
🗂️ 複数プロジェクト管理:バラバラ → 1ファイル統合
関連記事
Claude Codeで業務自動化を始めませんか?
Aurant TechnologiesはClaude Code導入から自動化設計まで無料相談を承っています。