過去一向使用 Google Apps Script(簡稱GAS) 存取 Google 試算表,可參考系列文章「用 GAS 操作試算表」,且「操作 Google Sheets API 讀取 Google 試算表」也說明過, Sheets API 無法對資料進行篩選、搜尋,所以不推薦使用。
而 GAS 雖然各種指令操作試算表都比 Sheets API 好用太多,而且不必解決麻煩的 oAuth 身份驗證問題,不過也還是有一些先天上的缺陷,例如有單日、單次執行的時間配額上限,另外一個硬傷就是 doGet、doPost 不容易 dubug,為了除錯必須在後台反覆重新發佈新版本,非常浪費時間缺乏效率。為了比較友善的程式碼開發環境,Sheets API 重新成為選項。
於是開始研究在本機 Windows 下,使用 Node.js 操作 Sheets API 存取 Google 試算表的方法。簡單說結論,如果只是簡單、重複性的 "寫入"試算表資料庫,沒有太複雜的試算表操作,Sheets API 會比 GAS 方便。而試算表 "寫入"以外的動作(包含 "讀取"),操作 GAS 內建的函數會方便且直覺很多。
本篇開發環境以「Sublime Text 3」(簡稱 ST3)舉例,說明如何以 Node.js 操作 Sheet API 對 Google 試算表進行讀取、寫入的實例操作。
(圖片出處: pxhere.com)
Ctrl + B 可執行程式碼,成功的話執行結果如下:
一、準備動作
從這個章節的準備動作開始,一直到「四、讀取試算表資料庫範例」之前的所有內容,都是 GAS 不需要的,用 Node.js 操作 Sheet API 的前置作業非常龐大,需要有一些心理準備。 1. Node.js如果對 Node.js 不熟悉的話,可參考這篇「Node.js 爬蟲開發新手技巧﹍GAS 替代品」,先把開發環境架構起來。 2. 啟用 Sheets API根據官網文件「Node.js quickstart」,說明了如何完整的操作流程,但全英文不容易理解,可直接閱讀以下的中文流程。 請參考這篇「取得 Google API 金鑰 流程」的流程:- 一、建立專案:還沒建立過專案的話,執行這個章節
- 二、啟用 Google API 服務:搜尋 Sheets API,並「啟用」
二、oAuth 憑證
1. 下載憑證接續前面的流程,啟用完 Sheets API 後,按上圖左側的「憑證」→ 上方「建立憑證」→ 選擇「oAuth 用戶端 ID」 本篇 Node.js 是在本機 Windows 執行,因此上圖請選擇「電腦版應用程式」,名稱隨意填寫,按下「建立」 出現上圖畫面,不必記錄這些資料,只需按「下載 JSON」存檔即可,但務必記住檔案名稱,之後程式碼會用到,本篇檔名以「credentials.json」作為範例。 2. 安裝 API接下來為 Node.js 安裝 Google API 與本機 auth 驗證,使用 Windows 命令字元 DOS 視窗,輸入以下指令進行安裝:npm i googleapis@105 @google-cloud/local-auth@2.1.0 --save -g
到這裡終於完成準備動作,可以開始寫程式了
三、oAuth 程式碼範例
以下程式碼範例來自官網,進行微調:const fs = require("fs").promises;
const path = require("path");
const process = require("process");
const {authenticate} = require("@google-cloud/local-auth");
const {google} = require("googleapis");
const SCOPES = ["https://www.googleapis.com/auth/spreadsheets"];
const TOKEN_PATH = path.join(process.cwd(), "token.json"); // 存放 refresh token
const CREDENTIALS_PATH = path.join(process.cwd(), "credentials.json"); // 下載的憑證檔案
// 檢查是否有 refresh token
async function loadSavedCredentialsIfExist() {
try {
const content = await fs.readFile(TOKEN_PATH);
const credentials = JSON.parse(content);
return google.auth.fromJSON(credentials);
} catch (err) {
return null;
}
}
async function saveCredentials(client) {
const content = await fs.readFile(CREDENTIALS_PATH);
const keys = JSON.parse(content);
const key = keys.installed || keys.web;
const payload = JSON.stringify({
type: "authorized_user",
client_id: key.client_id,
client_secret: key.client_secret,
refresh_token: client.credentials.refresh_token,
});
await fs.writeFile(TOKEN_PATH, payload);
}
// 如果首次執行先取得 refresh token, 非首次則直接根據 refresh token 產生 access token
async function authorize() {
let client = await loadSavedCredentialsIfExist();
if (client) {
return client;
}
client = await authenticate({
scopes: SCOPES,
keyfilePath: CREDENTIALS_PATH,
});
if (client.credentials) {
await saveCredentials(client);
}
return client;
}
- "credentials.json"即為前面「二、oAuth 憑證」下載的檔案,可改為自訂檔名,但務必跟執行的 .js 檔放在同一路徑
- "token.json"是程式自動產生的檔案,用來存放 refesh token,將來每次執行時用來產生 access token
- 執行 authorize() 會開始進行身份驗證流程,首次執行時會自動開啟瀏覽器,請按畫面指示開放權限即可。
- 首次執行完畢後會產生 refesh token,以後就不必再進行身份驗證
- 所以需好好保存這個 "token.json",當執行的 .js 檔放在別處時,最好也一併複製過去
四、讀取試算表資料庫範例
本篇範例一樣使用這個試算表作為舉例: 根據官網文件「Method: spreadsheets.values.get」,以下提供修改後的範例,這部分的程式碼,請接續在「三、oAuth 程式碼範例」的程式碼之後執行:const spreadsheetId = "106tP9D89pnEgvZTuM3_ahMJRPjCSD3qthth-GEhGMIE"; // 填入試算表 ID
const range = "sheet1!B1:D3"; // 填入的格式為 "工作表名稱!範圍"
async function readSheet(auth) {
const sheets = google.sheets({
version: "v4",
auth
});
const res = await sheets.spreadsheets.values.get({
spreadsheetId: spreadsheetId,
range: range,
});
const rows = res.data.values;
if (!rows || rows.length === 0) {
console.log("No data found.");
return;
} else {
console.log(JSON.stringify(rows));
}
}
authorize().then(readSheet).catch(console.error);
- spreadsheetId 請改為自己的試算表 ID,也就是試算表網址 "/d/ ~ /edit"之間的字串
- range 字串的格式為 "工作表名稱!範圍",參數如何修改可參考官網文件「Google Sheets API 總覽」
[["稱謂","性別","註解"],["Wayne","male","測試寫入功能"],["Mary","female","成功!"]]
五、寫入試算表資料庫範例
根據官網文件「Method: spreadsheets.values.update」,以下提供修改後的範例,這部分的程式碼,請接續在「三、oAuth 程式碼範例」的程式碼之後執行:const spreadsheetId = "填入試算表 ID";
const range = "填入工作表範圍";
const valueInputOption = "RAW"; // 儲存格資料格式
const values = [ // 寫入儲存格的資料
["稱謂", "性別", "註解"],
["Wayne", "male", "測試寫入功能"],
["Mary", "female", "成功!"]
];
async function saveSheet(auth) {
const sheets = google.sheets({
version: "v4",
auth
});
sheets.spreadsheets.values.update({
spreadsheetId: spreadsheetId,
range: range,
valueInputOption: valueInputOption,
requestBody: {
values: values
},
}, (err, res) => {
if (err) return console.log(`The API returned an error: ${err}`);
console.log(res.data);
});
}
authorize().then(saveSheet).catch(console.error);
- spreadsheetId 與 range 請參照「四、讀取試算表資料庫範例」的說明修改
- valueInputOption 參數修改可參考官網文件「ValueInputOption」,"RAW"為原始型態,"USER_ENTERED"系統會自動調整
- values 陣列填入所有儲存格內容,請注意每一列、每一欄的數量,必須符合 range 的設定,只要數目不吻合就會報錯,導致無法寫入試算表。
更多 Node.js 相關文章: