2026 全臺戶外教育季是 22 週的跨部會網頁活動,從規劃、設計到開發完成不到 2 個月。教育部攜手文化部、內政部國家公園署、農業部林業及自然保育署、環境部、經濟部、客家委員會、交通部觀光署、海洋委員會與原住民族委員會共同推出,另有民間團體參與。各單位以同一份 15 欄的調查表提供課程,共 11 張工作表。開發團隊用 Python 腳本把這些工作表整理成場域、課程、角色與問答四張表,再由 Node.js 匯入腳本逐列驗證後寫進資料庫。整理完成的資料有 187 個場域、476 堂課程與 1,056 題問答,互動地圖、課程列表、角色卡片與公告取用同一組編號。
整體的建置範圍見活動平台與後台,獎勵與帳務見有獎活動平台的帳務、防刷與預算控管。
10 個部會與民間團體
- 11 張工作表同一份 15 欄表頭
開發團隊
- Python 整理腳本欄位對照、場域合併、日期解析、編號排序
- 總表四張工作表場域、課程、角色、問答
- Node.js 匯入腳本第一輪驗證,第二輪寫入
活動網站與對外文件
- 互動地圖與課程列表依範圍、縣市、月份、星期、主題與部會查詢
- 角色卡片依總表批次輸出
- 公告與分享內文沿用同一組名稱與數字
只在總表改一次場域名稱、課程時間等內容改在源頭,重跑腳本後,地圖、課程列表與卡片取用更新後的資料。
範圍:活動期間用到的場域、課程、角色、問答與公告資料
調查表的合併與欄位對照
調查表的 15 欄含課程名稱、辦理地點、地圖地址、類型、簡介、活動時間、收費、報名窗口、主管機關、辦理單位與推薦亮點。腳本以 pandas 逐張讀取,只取前 15 欄,欄名去除換行後以關鍵字(例如 google、簡介、推薦亮點)對成固定的內部欄名,記下每列來自哪一張工作表,再合併成一個資料表,範例列與重複的表頭列同時移除。
| 原欄位 | 總表欄位 | 整理規則 |
|---|---|---|
| 課程名稱 | 課程名稱、課程編號 | 去除換行與空白,以名稱對上配對表取得課程編號 |
| 辦理地點、地圖地址 | 場域名稱、地址、Google Map 連結 | 統一寫法後建立場域,見下一節;連結由地址組成查詢網址 |
| 類型 | 課程分類 | 二十多種填寫選項對照成 8 類,生態環境最多,有 186 堂 |
| 活動時間 | 起始日、結束日、每週開放星期、時間備註 | 依規則解析,見活動時間一節 |
| 報名窗口 | 報名方式 | 含網址標為報名連結,只有信箱標為聯繫信箱,含電話標為聯繫電話 |
| 簡介、類型 | 標籤 | 以關鍵字對照表比對名稱、簡介與類型,沒有命中時以分類作標籤 |
合併後拆成場域與課程兩張表:場域表一列一個場域,課程表一列一堂課,匯入時課程以場域編號對上所屬場域。這是Wickham,2014整理的結構,每個變數一欄、每筆觀察一列、每種觀察單位一張表。地址、區域與歸屬單位只寫在場域表,場域有多堂課時,地址也只有一份。

場域的比對與合併
辦理地點先做正規化:去掉括號內的備註;全形逗號轉半形,連續空白併成一個;「臺」統一寫成「台」以便比對,地址在匯入時再統一為「臺」。正規化後的名稱是場域的鍵,名稱相同視為同一個場域,地址取第一筆有值的。
場域去重屬於重複紀錄偵測。Elmagarmid 等,2007指出,同一個實體在資料庫中常有兩種以上的表示方式,重複的紀錄之間沒有共同的鍵。調查表沒有共同的場域編號,編號由比對規則建立:一張 31 筆的合併對照表,把同棟或同園區的樓層、廳室、步道與不同寫法併入主場域;一張 18 筆的多地點對照表,把列出多個地點的課程歸入主場域,備註寫成「場地:含…」。
- 讀取辦理地點來自各單位的調查表
- 正規化去括號備註、全形轉半形、臺統一為台
- 同棟或同園區的樓層、廳室、步道併入主場域子地點寫進課程備註,格式「場地:…」
- 一堂課列出多個地點歸入主場域備註寫明另含哪些地點
- 不同物理位置各自保留為場域
地址另做標準化:取出括號中含縣市與門牌的正式地址,移除地圖網址,國字門牌改為阿拉伯數字(例如五號改為 5 號),Google Map 連結由整理後的地址組成。區域分北、中、南、東、離島五區,取自課程配對表;沒有對應時依地址判斷,比對順序是離島、北部、中部、南部、東部的縣市名稱。
每個場域另有 GPS 驗證範圍欄。座標先查人工座標表,其餘以地址(查不到時改用場域名稱)呼叫 Nominatim 地理編碼,請求間隔 1.1 秒,結果須落在緯度 21 至 27、經度 118 至 123 之內,再依場域類型換算成矩形範圍,187 個場域全部帶有驗證範圍。到場驗證以場域座標計算與使用者的距離。
歸屬單位(主管機關)由場域出現在哪一張調查表工作表判定:每張工作表對應一個正式單位名稱,場域名稱依手動指定、完全相符、包含關係、前四個字的順序比對,出現在兩張以上時由人工依課程數與相關程度決定。寫入後腳本驗證其餘欄位沒有被動到,歸屬彙總表的場域數與場域表一致。
下表是整理後的歸屬彙總。同樣算一個場域,可能是一間觀光工廠,也可能是一座國家公園,驗證範圍因此依場域類型換算。
| 主管機關 | 場域類型 | 數量 |
|---|---|---|
| 經濟部 | 觀光工廠、產業園區 | 56 |
| 交通部觀光署 | 風景區、旅遊服務中心 | 37 |
| 內政部國家公園署 | 國家公園、自然保護區 | 30 |
| 文化部 | 古蹟、博物館、文化園區 | 24 |
| 環境部 | 環境教育設施場所 | 17 |
| 農業部林業及自然保育署 | 森林遊樂區、自然教育中心 | 10 |
| 教育部 | 科學館所、園區、社區 | 6 |
| 海洋委員會 | 海洋教育場域 | 3 |
| 客家委員會 | 客家文化園區 | 2 |
| 原住民族委員會 | 原住民族文化園區 | 1 |
| 民間團體 | 食魚體驗館 | 1 |
| 合計 | 11 張工作表 | 187 |
活動時間的解析
活動時間在調查表是一格文字,腳本依下表的寫法判讀,星期與日期範圍各自解析,日期一律限制在 4 月 1 日至 8 月 31 日之間。
| 調查表的寫法 | 解析結果 |
|---|---|
| 星期,例如每週六、日,或平日、假日 | 寫入每週開放星期,1 至 7 代表週一至週日;平日為 1 至 5,假日為 6 與 7 |
| 月份區間,例如 4-8 月 | 起日為首月 1 日,迄日為末月最後一日,括號內說明寫入時間備註 |
| 單一月份 | 該月 1 日至月底 |
| 月/日的具體日期 | 取最早與最晚的日期為起訖,多日活動的原文寫入時間備註 |
| 含預約、申請或團體的描述 | 整個活動期間開放,原文寫入時間備註 |
| 其餘文字 | 有 4 至 8 月的月份就取該範圍,否則整個活動期間開放,原文前 50 字寫入時間備註 |
起訖日與星期在匯入時分別存成日期與 JSON 陣列。前台的月份篩選以起訖日區間是否與所選月份重疊判斷,星期篩選以陣列是否包含所選星期判斷,都在伺服器查詢時完成。
編號與排序
課程編號由區域碼、水陸碼與序號組成,例如 N-W-01 表示北部、水域的第 1 號。區域碼 N、C、S、E、I 依序是北、中、南、東與離島;水陸碼 W 與 L 是水域與陸域,由課程名稱、簡介、類型與地點中的水域關鍵字判斷,命中任一個為 W,其餘為 L。排序固定為區域、水陸、序號,最後是進化等級 Lv1 至 Lv3,排序腳本把每列轉成四個數字的排序鍵,排完逐列檢查沒有倒退。
課程表、配對表、角色表與問答表都以這個編號對應:匯入角色時依課程編號找到課程與場域,匯入問答時依編號找到角色。問答題同樣掛在角色編號之下。編號各段與角色圖的對應,見大型活動的角色系統怎麼設計。

角色表記的是場域編號,卡片上的場域名稱在輸出時才由場域表取得,場域改名只需改一處。W3C 的網路資料最佳實務建議資料集內的項目以持久的 URI 作為識別碼,才能和其餘資料集中關於同一個地方、人或事件的資料相連。這裡用的是活動內部編號,沒有網址形式,原則相同:同一堂課、同一個場域,在每張表裡用同一個識別碼對應。
重點課程與週曆
調查表最後一欄讓各單位標出推薦亮點,這一欄是重點課程的選取依據。腳本先依各區域的課程數比例分配名額,每區至少一個,再從該區候選課程中逐一選出得分最高者:推薦亮點先加分,再依場域、類型與來源單位的分布調整分數,使重點課程分散在不同的場域、主題與單位。
選出的課程標記寫回配對表,對應角色的稀有度一律設為最高。排程另存為週曆,每列記錄課程、來源單位、角色編號、開放日期、結束日期與開放週次。後端以日期區間加課程編號清單保存週曆,前台請求本週重點課程時,伺服器依臺灣時區的當日找出所在區間,回傳該週課程與對應角色。每週節奏與抽獎的配合見22 週活動的參與節奏。
公告與分享內文
活動橫跨 22 週,公告在開跑前先排成一份總覽,共約 37 則,每則寫好發布日期與管道,需依實際數據替換的欄位用紅色標出。
| 類別 | 則數 | 發布時機 |
|---|---|---|
| 活動前公告 | 1 | 開跑前預告 |
| 里程碑公告 | 6 | 開跑、首批重點課程開放、暑假特別企劃、排名中期、最終倒數、活動結束 |
| 每週抽獎結果 | 21 | 第 2 週至第 22 週,每週五晚間 9 點前發布 |
| 月抽加碼預告 | 5 | 四月至八月各一則,結果併入每週抽獎結果 |
| 領獎與行政 | 4 | 領獎流程、排名審核、總排名結果、未領獎催領 |

各單位協助轉載的內文也先寫好:基底是固定結構的活動說明,依序為活動資訊、活動亮點、獎品、參加步驟與聯絡資訊,再依官網、電子報、社群貼文等管道改寫成不同版本。每個部會另有一則專屬貼文,開頭寫該部會的場域數與類型,例如內政部國家公園署是 30 個國家公園與自然保護區場域,農業部林業及自然保育署是 10 個森林遊樂區與自然教育中心場域,數字與歸屬彙總表一致。對外一律寫 180 多個場域、470 多堂課,各單位轉載時出現的就是同一組數字。
匯入前的逐列驗證
總表分為場域、課程、角色、問答四張工作表,依這個順序由 Node.js 腳本匯入,後一張以前一張的編號對應。每支匯入腳本分兩輪:第一輪逐列驗證並蒐集全部錯誤,任何一列不合格就整批中止並列出列號與原因;全部通過才進入第二輪逐列寫入,因此驗證失敗時資料庫不會有任何一列被寫入。
- 讀取工作表依欄位順序轉成記錄
- 第一輪:逐列驗證蒐集全部錯誤,不在第一個錯誤就停止
- 全部通過第二輪:逐列寫入同時填入建立時間與狀態欄
- 任一列不合格整批中止列出列號與原因,資料庫維持原狀
| 工作表 | 第一輪的檢查與處理 |
|---|---|
| 場域 | 編號、名稱、地址、地圖連結、區域、歸屬單位與驗證範圍必填;區域須為五區之一;編號不重複;地址須解析出縣市與行政區 |
| 課程 | 編號、所屬場域編號、名稱、分類與說明必填;場域編號須已存在;編號不重複;日期轉為 YYYY-MM-DD;星期與標籤轉為 JSON 陣列 |
| 角色 | 課程編號、名稱與三段對話必填;稀有度與各階段數值須為 0 以上的整數;依課程編號關聯課程與場域 |
| 問答 | 角色編號須已存在;等級只能是 1 或 2;答案只能是 A、B、C;同一角色與等級不重複 |
資料異動與前台的查詢方式
腳本都可以重跑:讀原始工作表,寫出總表,並逐筆檢查課程的場域存在於場域表、起訖日落在 4 月 1 日至 8 月 31 日、每堂課都有編號與標籤,列出不通過的項目。批次異動改在總表並重跑腳本,個別欄位則在後台逐筆編輯,每次編輯都記錄操作者與變更內容。
地圖依畫面範圍的四個角座標查詢場域,同時帶回場域內的課程與角色。篩選條件有縣市(含鄉鎮市區)、月份、星期、主題與部會,關鍵字搜尋涵蓋場域名、課程名、簡介、標籤與歸屬單位。課程是否在開放期間由伺服器依臺灣時區的當日判斷,尚未開始的標示為即將開放。
角色卡片由 Playwright 啟動的無頭瀏覽器依總表逐張輸出,檔名由角色編號與等級組成,課程資料更新後重新輸出。活動結束後畫面自動換成結束版,地圖與圖鑑仍開放瀏覽。這類可重複產出的整理與檢查如何成為公部門專案的驗收證據,見公部門專案的交付與維運證據。

不適合的情況
- 只有單一單位、課程在幾十筆以內:試算表加人工核對即可。
- 內容必須逐字照原樣呈現,例如法規條文或公告原文:整理規則會統一寫法,這類內容不適用。
- 活動沒有地圖,也不做到場驗證:場域合併與座標整理可以大幅簡化,表頭與編號仍然需要。
開始前要準備什麼
需要備好的有五項:參與單位名單與窗口、要統一的表頭欄位、活動期間與各單位想推的重點課程、地圖是否需要到場驗證、對外文案的數字口徑。備齊之後,可以討論跨單位活動的資料與平台規劃。




