MapleCheng

在浩瀚的網路世界中無限潛水欸少年郎!

0%

用 Python 自動產出 Notion 工時報表:告別手動複製貼上

每個月底最痛苦的事是什麼?

對我們團隊來說是產出工時報表。

從 Notion 一筆筆複製到 Excel,調整格式,分類匯總……花兩小時做本該花十分鐘的事。而且每個月都要重來一次,整個過程讓我深刻體會到什麼是「重複性勞動的極致」。

這篇文章分享如何用 Python + Notion API 自動產出完整的工時 Excel 報表,包含明細、任務匯總、人員匯總三個 sheet。

需求背景

我們公司用 Notion 管理任務和工時。每個任務有:

  • 任務名稱、客戶代碼
  • 負責人
  • 工時(開始時間、結束時間)
  • 工作內容描述

月底需要產出 Excel 報表給會計,格式要求:

  1. 工時明細:每一筆工時紀錄
  2. 按任務匯總:每個任務的總工時
  3. 按人員匯總:每個人的總工時

以前是手動處理:

  1. 在 Notion 裡篩選客戶代碼
  2. 複製到 Excel
  3. 用樞紐分析表做匯總
  4. 調整格式

花兩小時,而且容易出錯。

解決方案

我寫了一個 Python script:scripts/notion_zzsq_timesheet.py

功能:

  1. 從 Notion timesheet database 撈資料
  2. 過濾特定客戶(例如 ZZSQ)
  3. 產出三個 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
notion = Client(auth=os.environ['NOTION_TOKEN'])

# 查詢 timesheet database
response = notion.databases.query(
database_id=TIMESHEET_DB_ID,
filter={
"property": "客戶代碼",
"rich_text": {
"contains": "ZZSQ"
}
}
)

# 轉換成 DataFrame
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:
# Sheet 1: 工時明細
df.to_excel(writer, sheet_name='工時明細', index=False)

# Sheet 2: 按任務匯總
task_summary = df.groupby('任務')['工時(分鐘)'].sum().reset_index()
task_summary.to_excel(writer, sheet_name='任務匯總', index=False)

# Sheet 3: 按人員匯總
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 的架構可以輕鬆擴展:

  1. 多客戶報表:改 filter 條件,一次產出多個客戶的報表
  2. 自動寄信:產出 Excel 後用 SMTP 或 Graph API 寄給會計
  3. 定期執行:用 cron 每月 1 號自動跑
  4. 視覺化:用 matplotlib 產出工時分佈圖

心得

寫這個 script 花了大概 1 小時,但每個月省 2 小時。兩個月就回本了,之後都是純賺。

這讓我深刻體會到:自動化不是「有時間再做」的事,而是「沒時間更要做的」事。

很多時候我們忙到沒時間優化工作流程,結果永遠在救火。花一點時間寫 script,長期下來省下的時間可以做更多有價值的事。

如果你也在做重複性的資料處理工作,不妨問問自己:「這個能用 script 自動化嗎?」

答案通常是肯定的。


完整程式碼scripts/notion_zzsq_timesheet.py(內部 repo,暫不公開)

如果這篇能幫你開始思考自動化,那我的時間就沒白花了。😄