每個月底最痛苦的事是什麼?
對我們團隊來說是產出工時報表。
從 Notion 一筆筆複製到 Excel,調整格式,分類匯總……花兩小時做本該花十分鐘的事。而且每個月都要重來一次,整個過程讓我深刻體會到什麼是「重複性勞動的極致」。
這篇文章分享如何用 Python + Notion API 自動產出完整的工時 Excel 報表,包含明細、任務匯總、人員匯總三個 sheet。
需求背景
我們公司用 Notion 管理任務和工時。每個任務有:
- 任務名稱、客戶代碼
- 負責人
- 工時(開始時間、結束時間)
- 工作內容描述
月底需要產出 Excel 報表給會計,格式要求:
- 工時明細:每一筆工時紀錄
- 按任務匯總:每個任務的總工時
- 按人員匯總:每個人的總工時
以前是手動處理:
- 在 Notion 裡篩選客戶代碼
- 複製到 Excel
- 用樞紐分析表做匯總
- 調整格式
花兩小時,而且容易出錯。
解決方案
我寫了一個 Python script:scripts/notion_zzsq_timesheet.py
功能:
- 從 Notion timesheet database 撈資料
- 過濾特定客戶(例如 ZZSQ)
- 產出三個 sheet 的 Excel 報表
核心程式碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| from notion_client import Client import pandas as pd from datetime import datetime
notion = Client(auth=os.environ['NOTION_TOKEN'])
response = notion.databases.query( database_id=TIMESHEET_DB_ID, filter={ "property": "客戶代碼", "rich_text": { "contains": "ZZSQ" } } )
rows = [] for result in response['results']: rows.append({ '日期': result['properties']['Date']['date']['start'], '任務': result['properties']['任務']['title'][0]['text']['content'], '人員': result['properties']['人員']['people'][0]['name'], '工時(分鐘)': calculate_minutes(result), '內容': result['properties']['內容']['rich_text'][0]['text']['content'] })
df = pd.DataFrame(rows)
|
產出三個 Sheet
1 2 3 4 5 6 7 8 9 10 11
| with pd.ExcelWriter(output_path, engine='openpyxl') as writer: df.to_excel(writer, sheet_name='工時明細', index=False) task_summary = df.groupby('任務')['工時(分鐘)'].sum().reset_index() task_summary.to_excel(writer, sheet_name='任務匯總', index=False) person_summary = df.groupby('人員')['工時(分鐘)'].sum().reset_index() person_summary.to_excel(writer, sheet_name='人員匯總', index=False)
|
執行方式
1
| python3 scripts/notion_zzsq_timesheet.py [output.xlsx]
|
不指定輸出檔名會用預設的 zzsq_timesheet_YYYYMMDD.xlsx。
實際成果
昨天執行結果:
- 142 筆工時明細
- 46 組任務匯總
- 2 人(Joe + 贾权)
整個過程從 2 小時縮短到 30 秒。
更重要的是,這個 script 可重複使用。下個月要產報表,只要再執行一次就好。
技術細節
Notion API 限制
Notion API 有分頁限制,每次最多回 100 筆。如果工時紀錄超過 100 筆,需要處理 next_cursor:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| all_results = [] cursor = None
while True: response = notion.databases.query( database_id=TIMESHEET_DB_ID, start_cursor=cursor, page_size=100 ) all_results.extend(response['results']) if not response['has_more']: break cursor = response['next_cursor']
|
工時計算
Notion 的 Date property 是 object,包含 start 和 end:
1 2 3 4 5
| def calculate_minutes(result): date_prop = result['properties']['Date']['date'] start = datetime.fromisoformat(date_prop['start']) end = datetime.fromisoformat(date_prop['end']) return int((end - start).total_seconds() / 60)
|
Excel 格式優化
為了讓報表更易讀,可以加一些格式:
1 2 3 4 5 6 7 8 9 10 11 12 13
| workbook = writer.book worksheet = writer.sheets['工時明細']
for column in worksheet.columns: max_length = 0 column_letter = column[0].column_letter for cell in column: try: max_length = max(max_length, len(str(cell.value))) except: pass worksheet.column_dimensions[column_letter].width = max_length + 2
|
延伸應用
這個 script 的架構可以輕鬆擴展:
- 多客戶報表:改 filter 條件,一次產出多個客戶的報表
- 自動寄信:產出 Excel 後用 SMTP 或 Graph API 寄給會計
- 定期執行:用 cron 每月 1 號自動跑
- 視覺化:用 matplotlib 產出工時分佈圖
心得
寫這個 script 花了大概 1 小時,但每個月省 2 小時。兩個月就回本了,之後都是純賺。
這讓我深刻體會到:自動化不是「有時間再做」的事,而是「沒時間更要做的」事。
很多時候我們忙到沒時間優化工作流程,結果永遠在救火。花一點時間寫 script,長期下來省下的時間可以做更多有價值的事。
如果你也在做重複性的資料處理工作,不妨問問自己:「這個能用 script 自動化嗎?」
答案通常是肯定的。
完整程式碼:scripts/notion_zzsq_timesheet.py(內部 repo,暫不公開)
如果這篇能幫你開始思考自動化,那我的時間就沒白花了。😄