Google apps script

2025 寒訓 - 吳綵芹 點點

GAS 編輯器操作

就是一些 起手式

開啟編輯器

< 方法一 > 從 Google Drive 開啟,開啟一個獨立的專案

  1. 進入 Google Drive (雲端硬碟)點選左上角新增
  2. 選擇 "更多" -> "Google Apps Script"
     

開啟編輯器

< 方法二 > 從已經存在的 Google 文件開啟,此為試算表示範。

  1. 建立 Google Sheets (試算表)
  2. 選擇左上角 "擴充功能" -> "Apps Script"

編輯器介面

各種功能簡單介紹一下

預設函式

選擇函式

添加檔案

其他差不多就是顧名思義

存檔

程式語言第一步!

GAS 操作

Hello World!

Logger.log('Hello World') ;
// 語法後面教
// 一樣記得字串引號
// 結尾分號

GAS 操作

存檔執行

成功長這樣

GAS 操作

然後就 成功了

Hello World!

javascript 基礎語法

Google Apps Script 語法以 JavaScript 為基礎。了解基礎 JavaScript 語法可以更快速學習 GAS 語法。

Index

變數賦值

變數 & 資料型別

var a = 0 ; // 一般變數
let b = 3 ; // 區塊變數
const c = 4 ; // 常數
let number = 42;                    // 數字
let string = "文字";                // 字串
let boolean = true;                // 布林值
let date = new Date();             // 日期
let array = [1, 2, 3];             // 陣列
let object = {name: "John"};       // 物件
let null = null;                   // 空值
let undefined;                     // 未定義

資料類型

陣列建立、存取、元素操作

陣列

let arr = [1, 2, 3] ;
// Logger.log() 為 GAS 語法
Logger.log(arr) ; // [1.0, 2.0, 3.0] 
Logger.log(arr[0]) ; // 1.0
arr.push(4) ; // 添加元素到陣列末
arr.unshift(0) ; // 添加元素到陣列前端
let last = arr.pop(); // 將末位元素儲存在變數 last 中,並從陣列移除
let first = arr.shift(); // 將第一個元素儲存在變數 first 中,並從陣列移除
let arr = [1, 2, 3, 4] ;
let double = arr.map(item => item * 2) ; // [2, 4, 6, 8]
let even = arr.filter(item => item % 2 === 0) ; // 條件判斷
arr.forEach(item => Logger.log(item)) ; // 逐一輸出

陣列操作

字串建立、操作

字串

let str1 = 'Hello' ;
let str2 = 'World' ;
let result = str1 + ' ' + str2 ; // Hello World
let template = `${str1} ${str2}!` ; // Hello World

let text = "  Hello World  ";
Logger.log(text.trim());                         // "Hello World"
Logger.log(text.toLowerCase());                  // "  hello world  "
Logger.log(text.toUpperCase());                  // "  HELLO WORLD  "
Logger.log(text.split(" "));                     // ["", "", "Hello", "World", "", ""]
Logger.log(text.replace("World", "GAS"));        // "  Hello GAS  "
Logger.log(text.includes("World"));              // true
Logger.log(text.substring(2, 7));                // "Hello"

物件建立:物件內可以建立資料、功能 (函式)

物件

let person = {
  name: "Laura",
  age: 16,
  address: {
    city: "Taipei",
    country: "Taiwan"
  }
};

person.email = "Laura@example.com"; // 新增屬性以及值
Logger.log(person.name); // Laura
Logger.log(person.address.city); // Taipei

物件操作,獲取所有屬性名稱、值

物件

let person = {
  name: "Laura",
  age: 16,
  address: {
    city: "Taipei",
    country: "Taiwan"
  }
};

let objectKeys = Object.keys(person); // [name, age,adress]
let objectValues = Object.values(person); // [Laura, 16.0, {city=Taipei, country=Taiwan}]

日期建立、基本操作

此為完整的表準日期格式:

 Sun Apr 12 13:28:56 GMT+0800 (CST)

日期

let now = new Date(); // 獲取現在日期
let newDate1 = new Date(2008, 3, 12, 13, 28, 56); // 建立日期 	Sun Apr 12 13:28:56 GMT+08:00 2008
let newDate2 = new Date(2008, 3, 12); // 可省略後面參數,自動設為 0 
let newYearDate new Date("2025-01-29") // 字串轉換日期,支援可以被 parse() 的字串格式

Logger.log(now.getFullYear());                   // 2025
Logger.log(now.getMonth());                      // 0-11
Logger.log(now.getDate());                       // 1-31
Logger.log(now.getDay());                        // 0-6 (週日-週六)
Logger.log(now.getHours());                      // 0-23
Logger.log(now.toLocaleDateString());            // 本地日期字串

let tomorrow = new Date(now.getTime() + 24*60*60*1000);
let diffDays = Math.floor((tomorrow - now) / (24*60*60*1000));

函式

// 基本函式
function basicFunction(a, b) {
  return a + b;
}

const basicFunction = function(a, b){
  return a + b ;
}

// 箭頭函式  
const arrowFunction = (a, b) => {
  return a + b;
};
// 只有回傳值可以簡寫成這樣
const arrowFunction = (a, b) => a + b;

// 呼叫函式
Logger.log(arrowFunction(10, 20)); // 30

函式名稱

參數

運算子

算數運算子與 C++ 的寫法基本相同,這邊簡單說明比較運算子的部分。

運算子 說明 舉例
== 等於 3 == '3' (true)
!= 不等於 3 != 2 (true)
=== 全等(等於並且型別相等) 3 === '3' (false)
!== 不全等 2 !== '2' (true)
> 大於 3 > 2 (true)
< 小於 3 < 4 (true)
>= 大於等於 3 >= 3 (true)
<= 小於等於 4 <= 4 (true)

判斷式

// if 條件判斷
if (condition) {
  // 程式
} else if (anotherCondition) {
  // 程式
} else {
  // 程式
}
// switch 條件判斷
switch (value) {
  case 1: // 當 value 等於 1,執行程式
    // 程式
    break;
  case 2:
    // 程式
    break;
  default:
    // 程式
}

迴圈

let arr = [1, 2, 3, 4];
for (let i = 0; i < arr.length(); i++){
  Logger.log(arr[i]);
} // 1, 2, 3, 4
for(let key in arr){
  Logger.log(key);
} // 0, 1, 2, 3
for(let item of arr){
  Logger.log(item);
} // 1, 2, 3, 4

for...in 迴圈拿來遍歷物件的 Key 放在陣列上的話就是索引值。

for...of 迴圈拿來遍歷物件的 Value 以陣列來說就是儲存的值。

迴圈

let arr = [1, 2, 3, 4];
let i = 0;
while (i < arr.length()) {
  Logger.log(arr[0]);
  i++;
}

do {
  Logger.log(arr[0]);
  i++;
} while (i < arr.length());

do...while 迴圈是先執行一次再判斷,while判斷式後面記得加分號。

JavaScript

基礎語法完結!!!

Google apps script語法

呵呵終於要進入正題了

Index

一打開長這樣

GAS

function myFunction() {
  // 程式寫在這,GAS 每個 function 單獨執行
}
// 後面可以寫別的函式,並且可以獨立執行。

開啟試算表

試算表

// 取得活動中的試算表 
let spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
let sheet = spreadsheet.getActiveSheet(); // 獲取活動中工作表
// 開啟試算表 
let spreadsheet = SpreadsheetApp.openById('試算表ID');
let sheets = spreadsheets.getSheets(); // 獲取所有工作表

當你的 .gs 檔有跟試算表連在一起,並且試算表開啟的時候可以直接獲取活動中的試算表。

否則通常完整的寫法使用 id 開啟試算表。

建立新試算表

試算表

// 建立新試算表並命名
let newSpreadsheet = SpreadsheetApp.create('試算表名稱');
// 建立新工作表
let newsheet = newSpreadsheet.insertSheet('newSheet'); 
// 獲取試算表 id
let spreadsheetId = newSpreadsheet.getId();
// 獲取試算表 URL
let spreadsheetUrl = newSpreadsheet.getUrl();

讀取儲存格

試算表

let spreadsheet = SpreadsheetApp.openById('試算表ID');
let sheets = spreadsheets.getSheets(); // 獲取所有工作表,以陣列儲存
// 讀取儲存格資料
// 讀取單一儲存格
let value = sheets[0].getRange("A1").getValue();
let value = sheets[0].getRange(1, 1).getValue();  // 同上,使用儲存格座標
// 讀取多個儲存格
let values = sheets[0].getRange("A1:B5").getValues();
let values = sheets[0].getRange(1, 1, 5, 2).getValues();  // 同上,使用儲存格座標

讀取多個儲存格時,將資料轉換成陣列。

寫入儲存格

試算表

let spreadsheet = SpreadsheetApp.openById('試算表ID');
let sheets = spreadsheets.getSheets(); // 獲取所有工作表,以陣列儲存
// 寫入儲存格資料
// 寫入單一儲存格
sheets[0].getRange("A1").setValue("新資料");

// 寫入多個儲存格
let data = [["姓名", "年齡"], ["小明", 3]];
sheets[0].getRange(1, 1, 2, 2).setValues(data);
1,1 (A1) 1,2 (B1) 1,3 (C1) 1,4 (D1) 1,5 (E1)
2,1 (A2) 2,2 (B2) 2,3 (C2) 2,4 (D2) 2,5 (E2)
3,1 (A3) 3,2 (B3) 3,3 (C3) 3,4 (D3) 3,5 (E3)

傳送郵件

GMail

// 發送郵件一
GmailApp.sendEmail(
  "recipient@example.com",
  "郵件主旨",
  "郵件內容"
);
// 發送郵件二
MailApp.sendEmail(
  "recipient@example.com",
  "郵件主旨",
  "郵件內容"
);
// 字串轉換
`${變數}`

GmailApp vs MailApp

GMail

功能 GmailApp MailApp
傳送郵件
寄件備份
讀取郵件
搜尋、刪除郵件
傳送附件
是否需要授權
傳送上限
 

個人:100 封
Workspace:1500 封

個人:100 封
Workspace:1500 封

Gmail

缺點

  • 不會保留寄件副本
  • 無法存取 Gmail 郵件、標籤

優點

  • 適合傳送簡單郵件,方便快速
  • 不需要 Gmail 權限

MailApp

使用情境

不需要存取 Gmail 郵件

不想或不能請求權限

正在 Google Workspace 環境中

Gmail

缺點

  • 需要 Gmail 權限
  • 較為適合個人帳號

優點

  • 可以操作進階 Gmail 功能
  • 寄件後會保留備份
  • 可以發送附件

GmailApp

使用情境

需要保留寄件備份

需要讀取、搜尋、刪除郵件,或修改標籤

需要傳送附件

傳送 HTML 格式郵件

也可以用 MailApp

GMail

// 發送 HTML 格式郵件
GmailApp.sendEmail(
  "recipient@example.com",
  "郵件主旨",
  "",
  {htmlBody: "把 HTML <body> 內容搬過來"}
);

也可以把整個 HTML 標籤內所有東西搬過來,這樣就可以使用內嵌 CSS 以及 JS,不過不保證成功。

搜尋郵件

GMail

// 搜尋來自指定寄件人的郵件
let threads = GmailApp.search('from:example@example.com');

搜尋條件

 'suject:remind' 搜尋特定主題的郵件

'has:word' 搜尋包含特定文字的郵件 

'to:Laura@example.com' 搜尋特定收件人的郵件

獲取郵件內容

GMail

// 搜尋來自指定寄件人的郵件
let threads = GmailApp.search('from:example@examp');
threads.forEach((thread)=>{
  let messages = thread.getMessages();
  messages.forEach((message)=>{
    let subject = message.getSubject();
    Logger.log('主題: + `${subject}`');
  })
})

讀取資料

getFrom(), getTo(), getDate(), getBody(), getSubject()

 收件人      寄件人        日期       郵件內容        主旨       

建立一個試算表,裡面包含一些人物資訊,至少有姓名跟郵件(可以借你隔壁的用一下),請依據試算表內容發出至少兩封信件,信件裡面須包含試算表裡的資訊。

小實作

必須包含主旨,其餘內容不拘,舉例:XXX您好,這是一封測試信。

 Google Form 同樣可以直接建立一個與其連結的 Apps Script ,並且其本身可以建立試算表,獲取資料的方式就和前面所說的相同。

form

// 建立新表單
function createNewForm(formName) { // 呼叫函式時需包含一個參數 formName
  let newForm = FormApp.create(formName); // 建立新的表單
  let formId = newForm.getId(); // 獲取新表單的 id
  return formId ; // 回傳 id,是一個字串
}
// 以 id 開啟表單
let form = FormApp.openById(formId);

// 開啟活動中的表單
let form = FormApp.getActiveForm();

 Google Form 建立時,在獲取 URL 的時候比較特殊,分為編輯以及填寫兩種連結。

form

// 建立表單
function createNewForm(formName) { // 呼叫函式時需包含一個參數 formName
  let newForm = FormApp.create(formName); // 建立新的表單
  let editUrl = newForm.getEditUrl(); // 獲取編輯連結
  let publishedUrl = newForm.getPublishedUrl(); // 獲取公開連結
  let Urls = {
    edit: editUrl,
    published: publishedUrl
  }; // 建立 Url 物件,儲存兩種連結。
  return Urls ; // 回傳
}

建立問題(這裡以單選問題舉例)

form

// 建立新問題
let form = FormApp.openById(id);
let item = form.addMultipleChoiceItem();
item.setTitle("你最喜歡的動物?");
item.setChoices([item.createChoise("貓"), item.createChoise("狗")]);
item.showOtherOption(true);

還可以建立什麼?

多選題

簡答題

下拉選單

勾選方塊

圖片

標題

段落題

多選網格題

影片

單選網格題

獲取表單回應

form

function getFormResponses() {
  let form = FormApp.getActiveForm();
  let responses = form.getResponses();
  responses.forEach((response) => {
    let answers = response.getItemResponses();
    answers.forEach((answer) => {
      Logger.log("問題:" + answer.getItem().getTitle());
      Logger.log("回應:" + answer.getResponse());
    });
  });

建立一個表單(用 Apps Script) ,裡面可以填寫日期、科目、成績,根據表單結果每日自動化發送成績報表郵件給自己 (你想傳給你們班導或爸媽我也沒意見)

小實作

建立新行事曆活動

Calendar

function createCalendarEvent() {
  let calendar = CalendarApp.getDefaultCalendar(); // 取得預設行事曆
  calendar.createEvent("GAS課", // 事件標題
    new Date(2025, 1, 4, 9, 0), // 開始時間(2025年2月4日 9:00)
    new Date(2025, 1, 4, 12, 0), // 結束時間(2025年2月4日 12:00)
    { location: "北一女中學珠五樓電腦教室", description: "建北電資寒訓 GAS 課程.." } // 其他資訊
  );
}

取得特定日期的所有活動

Calendar

function getEventsOnDate() {
  let calendar = CalendarApp.getDefaultCalendar();
  let startTime = new Date(2025, 1, 4); // 2 月 4 日
  let endTime = new Date(2025, 1, 5);   // 2 月 5 日(跨一天以取得當天所有事件)

  let events = calendar.getEvents(startTime, endTime);
  events.forEach(function(event) {
    Logger.log("標題: " + event.getTitle() + ", 時間: " + event.getStartTime());
  });
}

刪除特定事件

Calendar

function deleteEvent() {
  let calendar = CalendarApp.getDefaultCalendar();
  let startTime = new Date(2025, 1, 5, 10, 0);
  let endTime = new Date(2025, 1, 5, 11, 0);

  let events = calendar.getEvents(startTime, endTime);
  events.forEach(function(event) {
    if (event.getTitle() === "會議") { // 確保是要刪除的事件
      event.deleteEvent();
      Logger.log("已刪除事件:" + event.getTitle());
    }
  });

建立一個 Form (這邊為了方便可以手動建立),裡面是關於日程的問題,例如:活動名稱、時間、參與人...,根據此表單的填寫結果,自動化建立日歷活動。

小實作

Google Apps Script

WEB

可以寫後端!!!

可以架設網頁!!!

Step1:有一個 HTML 檔

Step2:引入到 Apps Script

WEB

Step3:寫好後端

WEB

function doGet() {
  // 載入並返回 HTML 頁面
  return HtmlService.createHtmlOutputFromFile('index'); 
  // index 為網頁 html 名稱
}

Step4:部署

WEB

Step4:部署

編輯權限

WEB

獲得一個連結,然後就成功啦!!!

WEB

介紹 doGet 在幹嘛,主要功能就是回傳HTML 頁面,處理 HTTP GET 請求

WEB

function doGet() {
  // 載入並返回 HTML 頁面
  return HtmlService.createHtmlOutputFromFile('index'); 
  // index 為網頁 html 名稱
}

接下來就可以用 GAS 處理網頁後端,我們可以結合試算表儲存資料。

與一般 HTML 的檔案不同的是,這裡的 script 寫在 head

WEB

<!DOCTYPE html>
<html>
  <head>
    <title>Google 試算表填寫</title>
    <script>
      function submitForm() {
        let name = document.getElementById("name").value;
        let email = document.getElementById("email").value;

        google.script.run.withSuccessHandler(() => alert("提交成功!")).saveData(name, email);
      }
    </script>
  </head>
  <body>
    <h1>請填寫資訊</h1>
    <label>姓名:</label> <input type="text" id="name"><br>
    <label>Email:</label> <input type="text" id="email"><br>
    <button onclick="submitForm()">提交</button>
  </body>
</html>

gs這樣寫

WEB

function doGet() {
  return HtmlService.createHtmlOutputFromFile("index");
}

function saveData(name, email) {
  let sheet = SpreadsheetApp.openById("你的試算表ID").getSheetByName("表單回應");
  sheet.appendRow([name, email, new Date()]);
}

依樣畫葫蘆,把表單填寫內容結合 Gmail 傳送一個確認信件給填寫人。

小實作

參考資料

成發

每個人都要做一份個人的 GAS 成發呦~

進度追蹤系統

可以是各種進度,閱讀、跑步、念書、成績......

使用者填寫每日進度(可以用 form 或者 sheet)

每日提醒使用者更新進度

進度落後發送提醒訊息給使用者 (可以用我教過的郵件、或者 google 有自己的訊息系統可以嘗試看看)

定期生成圖表 (試算表功能) 傳送報告給使用者

成發

進階

把以上東西搬到網頁上,用 GAS 寫,可以參考完簡報後,寫 HTML 和 CSS。

 

其他

引入外部 API (可適當使用 AI 工具) 

成發

Google Apps Script

By laura07110717

Google Apps Script

  • 94