過去一向使用 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 相關文章:
看著看著不知不覺就變成跪著看了
回覆刪除(哎呀填錯留言表單了真害羞www