GAS ビギナーが GAS を使いこなすために知るべきこと 10 選

## はじめに

[Google Apps Script](https://qiita.com/tanabee/items/e51f107f1e95a42cc636#google-apps-script-とは) (GAS) は Web ブラウザ上の JavaScript とも Node.js とも環境が異なります。その違いや、 GAS 特有の機能を理解するとさらに開発が捗るので、それらをこの記事で紹介しようと思います。

[Tokyo GAS](https://qiita.com/tanabee/items/d478276e281045e37076) で 5 分 LT した内容です。

スライドはこちら > [GAS ビギナーが GAS を使いこな すために知るべきこと 10 選](https://speakerdeck.com/tanabee/for-google-app-script-begginers)

※より網羅的で最新の情報を得たい方は DevFest 2020 の登壇動画 [Google Apps Script 入門 2020](https://youtu.be/aBGnfrfBFEc) をご覧ください。

## 1. ローカル環境で開発する

GAS を好きなエディタで開発したり、ローカルで開発したものを github に上げたりしたくなる。

Google ブログの記事 [Apps Script による高度な開発プロセス](https://developers-jp.googleblog.com/2016/01/apps-script.html) で紹介されているが、 [node-google-apps-script](https://github.com/danthareja/node-google-apps-script) という npm パッケージをローカル環境にグローバルインストールことで、ローカルで開発したものを GAS に push することができる。

```JavaScript:node-google-apps-script
// clone
$ gapps clone <scriptId>
// push
$ gapps push
```

[clasp](https://github.com/google/clasp) というライブラリだと push だけでなく pull もできたり、コマンドも豊富なので、 clasp の方が良さげ。

```JavaScript:clasp
// clone
$ clasp clone <scriptId>
// push
$ clasp push
// pull
$ clasp pull
```

## 2. github でソースコードを管理する

1. の方法でローカルで開発する場合は、その状態を github と連携してソースコード管理すれば良い。もう一つの方法としては、 [Google Apps Script Github アシスタント](https://chrome.google.com/webstore/detail/google-apps-script-github/lfjcgcmkmjjlieihflfhjopckgpelofo?hl=ja) という Chrome Extension があるので、これを使えば、 github に push / pull することができる。

![スクリーンショット 2018-04-01 10.11.53.png](https://qiita-image-store.s3.amazonaws.com/0/19698/adf09434-0d89-dd25-0c93-9488272efe38.png)

## 3. 複数の *.gs 間で関数を呼び出す

GAS では複数の *.gs ファイルを持つことができる。これらの関数はグローバル関数となるので、そのまま他のファイルで呼び出すことができる。以下のように書くと util.gs の add 関数は正常に呼び出せる。

```JavaScript:main.gs
function main() {
  var num = add(1, 2);
  Logger.log(num);
}
```

```JavaScript:util.gs
function add(a, b) {
  return a + b;
}
```

グローバル関数となるので、複数ファイルで同一の名前の関数名をつけてはならない。

## 4. 様々な実行方法

GAS では、主に以下の実行方法から選択する。

* トリガー
* G Suite アプリケーションの特定のイベントをハンドリング
* Web 公開

### トリガー

毎週月曜の朝に実行するような場合はトリガーを利用する。 Heroku でいう Scheduler みたいなもの。タイマー（分/時/日/週/月）を利用して、実行タイミングを細かく指定できる。`編集` > `現在のプロジェクトのトリガー` から設定する。

![スクリーンショット 2018-03-21 16.43.37.png](https://qiita-image-store.s3.amazonaws.com/0/19698/a87e17e2-11cf-9d3b-27b8-5d6af7171841.png)

トリガーの例: [Google Apps Script (GAS) で毎週 30 分の雑務を自動化した話](https://qiita.com/tanabee/items/e51f107f1e95a42cc636)

### G Suite アプリケーションの特定のイベントをハンドリング

* 特定の Docs を開いた時
* スプレッドシートの更新時
* Google フォームの回答時

など、様々なタイミングで実行することができる。公式の [Event Objects
](https://developers.google.com/apps-script/guides/triggers/events) で補足できるイベントと、イベント発火時に渡される値を知ることができる。

### Web 公開

`公開` > `ウェブアプリケーションとして導入` を選択すると、公開することができる。簡単な API を作って公開することができ、これはかなり強力。

![スクリーンショット 2018-03-21 17.54.30.png](https://qiita-image-store.s3.amazonaws.com/0/19698/776a712c-c40d-2f7a-c3dc-57603ca891b9.png)

公式の [Web Apps](https://developers.google.com/apps-script/guides/web) の通り、GET の場合は doGet 関数、 POST の場合は doPost 関数を実装する必要がある。ミニマムな GET, POST API 実装を以下に記述する。

```JavaScript:minimum-api.gs
function doGet(e) {
  return ContentService.createTextOutput("hello world!");
}

function doPost(e) {
  return ContentService.createTextOutput("OK");
}
```

返り値は TextOutput か HtmlOutput のいずれかである必要がある。 HtmlService と絡めると、 html を公開できるので、簡単な Web アプリケーションを提供することも可能。

Web 公開の例: [3 分で作る無料の翻訳 API with Google Apps Script](https://qiita.com/tanabee/items/c79c5c28ba0537112922)

## 5. スクリプト毎のデータストアがある

前回の実行結果など、スクリプト毎に簡単なデータを保存する保存領域が用意されている
。公式ドキュメントはこちら [Class PropertiesService | Apps Script](https://developers.google.com/apps-script/reference/properties/properties-service) 。

以下のように呼び出せる。

```JavaScript
var properties = PropertiesService.getScriptProperties();
properties.getProperty(key);// 取得
properties.setProperty(key, value);// 設定
properties.deleteProperty(key);// 削除
```

これで、スクリプトの途中結果を保存して、次の実行時に利用する値を参照できる。


## 6. スクリプトからトリガーをセットできる

[TriggerBuilder](https://developers.google.com/apps-script/reference/script/trigger-builder) を使ってスクリプトからもトリガーを設定できる。以下のコードは、 `1 分後` に `main` という名前の関数を実行するトリガーを登録している。

```JavaScript
var functionName = 'main';
var d = new Date();
d.setMinutes(d.getMinutes() + 1);// 1 分後
ScriptApp.newTrigger(functionName).timeBased().at(d).create();
```

## 7. 実行時間の制限と対策

1 回の実行で 6 分間の時間制限があり、スクリプトの実行途中でも強制的に終了する。 6 分を超える場合には以下のような対策が取れる。

例として、スプレッドシートに対して各行処理するスクリプトだとすると

1. 実行時間が 5 分になるのを検知
2. 次回処理を開始する行数を PropertiesService で保存
3. TriggerBuilder を使って新しいトリガーを 1 分後に設定
4. 処理を終了させる

これは、上の 5, 6 で紹介した Tips を用いた方法。 5 分や 1 分という値は仮なので、よさげな値を使ってください。

その他の制限は公式ガイドの [Quotas](https://developers.google.com/apps-script/guides/services/quotas) を参照。


## 8. G Suite 以外のサービスの API をたたく

GAS は G Suite のアプリケーションを簡単に操作できるが、[UrlFetchApp](https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app) を使って外部サービスとの連携も簡単にできる。

例として　Slack にメッセージ投稿するコードを以下に示す。

```JavaScript:Slack連携
function postSlack(slackWebhookUrl) {
  var body = { text: 'message' };
  var payload = JSON.stringify(body);
  var res = UrlFetchApp.fetch(slackWebhookUrl, {
    method: 'POST',
    headers: { "Content-Type": 'application/json' },
    payload: payload
  });
}
```

## 9. Web スクレイピングの方法

GAS における Web スクレイピングは以下の流れで行う

1. UrlFetchApp.fetch で html を取得
2. html を parse

1　は直前で紹介したので省略する。 2　については、 GAS 公式の [Parsing HTML](https://sites.google.com/site/scriptsexamples/learn-by-example/parsing-html) で紹介された方法で Web ブラウザ上の JavaScript のような HTML のパースができるが、 XmlService を使っているため、エラーになる場合も多い。

2022年9月時点では [cheerio](https://cheerio.js.org/) を Google Apps Script 上で動作するようにライブラリ化された [tani/cheeriogs](https://github.com/tani/cheeriogs) を利用するのが良い選択肢だと思われる。

[tani/cheeriogs](https://github.com/tani/cheeriogs)　の README の通りライブラリ読み込みを行った上で以下のようにパースできる。

```JavaScript
// TODO: 別途ライブラリの読み込みが必要
const content = UrlFetchApp.fetch('https://en.wikipedia.org').getContentText()
const $ = Cheerio.load(content)
Logger.log($('#mp-right').text())
```

ちなみに、スクレイピングのマナーとして `1 秒間に 1 回しかアクセスしない` というものがあるが、 GAS で sleep するには、 [Utilities](https://developers.google.com/apps-script/reference/utilities/utilities) クラスの sleep を呼び出す。そもそもクローリング拒否してるかどうかは robots.txt を見て判断する。

```JavaScript
Utilities.sleep(1000);
```

Utilities は GAS に適した便利関数群が用意されているので、一度眺めてみるのを勧める。


## 10. GAS ライブラリの仕組み

GAS で npm モジュールを使えれば非常に便利なのだが、普通に npm install しても動作しない。*ローカルでコンパイルするといける方法はあるそうなので、後日調べたら記事化します*

代わりに GAS にはライブラリという仕組みがあり、他の人が作った GAS ライブラリを呼び出したり、自分の GAS を登録することができる。詳しくは公式の [Libraries](https://developers.google.com/apps-script/guides/libraries) に書かれている。

## まとめ

ここ数ヶ月で GAS を始めて、調べていて有益だと思った情報をまとめました。私もまだまだ勉強中なので、またネタを仕入れたら記事書きます。

## 他の GAS ネタ

- [Google Apps Script でよく使うスニペット集 30 選](https://qiita.com/tanabee/items/5de3e8715be759ce1c7f)
- [スプレッドシートに OKR を書くとツリー構造で可視化されるツールを作ってみた](https://qiita.com/tanabee/items/3c17dcdbb8efb7afe212)
- [毎月 500 時間の社内ルーティンワークを GAS を使って自動化した話](https://qiita.com/tanabee/items/ce9c3cf9403c4f3f14a9)
- [3 分で作る無料の翻訳 API with Google Apps Script](https://qiita.com/tanabee/items/c79c5c28ba0537112922)