Getting Started with Google App Script (1) – 認識及使用 Google App Script

撰文的當下我在 Google 擔任 Developer Relations Program Manager 的職務,並非 Google Cloud、G Suite 或 App Script 的產品單位,所以內容僅是個人學習心得及經驗(我也還是個初學者),正確內容請參考官方的公開文件

前言

因為在公司內許多工作都大量使用 G Suite(廢話),而我自己有時也會使用 Google App Script 來自動化一些工作流程、或是用來剖析在 GMail、Google Docs 等文件中的資料。所以打算把自己研究學習的心得記錄及分享出來,希望也能幫助到大量使用 G Suite 的團隊。

什麼是 Google App Script

Google App Script (GAS) 顧名思義,就是一個用來操作「Google Apps」的腳本語言(scripting language),舉凡是 Google Docs、Google Spreadsheet、Google Presentation 這些文件,甚至包括 GMail、Google Drive 這些服務也能運用 Google App Script 來進行操作。

Google App Script 是以 ECMAScript 5 (ES5) 為基礎,執行環境為 V8 引擎(參考:V8 Runtime overview),所以對於熟悉 JavaScript 語言的開發人員來說,要上手 Google App Script 是易如反掌。而你寫好的「程式」(其實是 script)是在 Google 的伺服器環境中執行,這部份是完全免費的,不過也就可想而知它會有不少限制(參見:Quota for Google Services),所以雖然它能操作許多 Google 文件,也能透過 HTTP(S) 連線呼叫外部的 API 與其它服務互動、甚至還能做成一個簡單的 web application,但作為輕量級的自動化操作、剖析文件內容、擴充功能等等的操作還可以,但要拿來開發 mission-critical 的服務或系統就不適合了。

從範例開始:整合外部資料更新 Google Spreadsheet 內容

這裡直接用一個範例來介紹 Google App Script 是怎麼運作的,我會做一個簡單的 Google Spreadsheet,然後放上幾個世界大城市的名稱,再藉著呼叫 OpenWeatherMap 的 API 來取得溫度及溼度資料,並且儲存到對應的表格中。這個表格長得像這樣:

一個簡單的表格,每列 (row) 表示該城市的資料

打開 Script Editor

有了這個表格後,就直接在這個表格中加入 Google App Script,直接在文件的選單列找到 Tools > Script Editor(如果是中文介面,會是 工具 > 指令碼編輯器),點選後進入 Google App Script 的「IDE」中:

Google App Script 的編輯器畫面

接下來我們就把程式碼更新在 Code.gs 的檔案內容裡,並且把函式名稱改成 updateWeather

function updateWeather() {
  // 取得 spreadsheet instance
  let sheet = SpreadsheetApp.getActiveSpreadsheet();
  
  // 讀取 spreadsheet 中的資料,rawData 就會是一個 2-dim array
  let rawData = sheet.getDataRange().getValues();

  // 因為第一列是 header,所以先把它移開,暫存在 header 中
  let header = rawData.shift();
  
  // 呼叫 OpenWeatherMap 的資料格式
  let url = 'https://api.openweathermap.org/data/2.5/weather?appid=[換成你的OpenWeatherMap API Key]&q=';
  
  // 處理每一列資料
  for (let i = 0; i < rawData.length; ++i) {
    // rawData[i][0] 就是城市名,所以用來拼到 query string 中
    let realUrl = url + rawData[i][0];
    // 運用 UrlFetchApp 來呼叫 OpenWeatherMap 的 API
    let resp = UrlFetchApp.fetch(realUrl).getContentText();
    // 將回傳的 JSON text 轉換成 JavaScript object
    let json = JSON.parse(resp);
    
    // 把溫度資料寫在第二欄
    rawData[i][1] = json.main.temp / 10.0;
    // 把溼度資料寫在第三欄
    rawData[i][2] = json.main.humidity;
    // 把時間寫在第四欄
    let today = new Date();
    rawData[i][3] = `${today.getFullYear()}-${today.getMonth()+1}-${today.getDate()} ${today.getHours()}:${today.getMinutes()}:${today.getSeconds()}`;
  }
  
  // 把 header 放回 rawData 的第一列
  rawData.unshift(header);
  // 把 rawData 覆蓋回原本的表格中
  sheet.getDataRange().setValues(rawData);
}

你也許會想問,我只能使用一個檔案來寫 script 嗎?能不能拆成多個 .gs 檔呢?答案是可以的,不過它並不像其它 JavaScript 執行環境有模組的概念,Google App Script 在執行時會把所有的 .gs 檔一起載入到 global namespace 下,所以拆成多個檔案沒有問題,不過如果遇到相同名稱的函式就會有不可預期的結果,所以建議在拆成多個檔案後,可以多利用 class 來進行 scope 的分離。

呼叫這個 script

程式雖然簡單地寫完了,但還沒有讓它動起來,我們先用一個簡單的方法:在原本的表格中放一個按鈕,按下按鈕後觸發這個 script。你可以在 Google Spreadsheet 的選單中使用 Insert > Drawing 來「畫」一個按鈕:

放一個按鈕在 spreadsheet 中

點擊按鈕後,在按鈕的右上角可以叫出選單,在選單中選擇 Assign script,然後填成 updateWeather

為按鈕加上 script

完成後,按下按鈕就可以看到表格更新了,不過第一次執行這個 script 時會要求授權,因為 Google App Script 雖然是在 Google 的伺服器上執行,但它必須用你的身份來執行,所以會走一次授權的流程

第一次執行時,為了取得你身份的代理,就會進行一次授權流程

執行結果就會像是這樣:

Col 1,2,3 是由 App Script 更新的

如何讓它定時執行

前一段用了一個按鈕呼叫 script,不過 Google App Script 還是可以設定在固定時間呼叫 script,你只要開啟 https://script.google.com/ 然後開啟剛才開發的專案,在 PROJECT DETAILS 的選單下可以找到一個 Triggers,這裡就是設定觸發條件的地方。

設定 script 的觸發條件

在 Triggers 中加入一個 Trigger,把 event source 設定為 Time-driven,就可以定期執行你所指定的函式了,像這樣就是每個小時呼叫一次 updateWeather

除錯及監控

你可以在 PROJECT DETAILS 的選單中點到 Executions 的部份,這裡會詳實記載 script 每一次的執行,如果你想在程式中某處插入 log,可以直接呼叫 Logger.log() 來操作,也會把 log 放在執行結果中喔。

系列連載

接下來,我就會挑選一些沒有敏感機密資料,而我有時在工作時會運用 Google App Script 的情境與範例分享在此系列中,如果你也有興趣的話,歡迎繼續關注,瞭解 Google App Script 可以做哪些有趣的加值應用吧!

This Post Has One Comment

  1. Bo-Yan Cheng

    多個 *.gs 讀取順序也很頭大。

Leave a Reply