【初心者向け】GASでニュース記事をSlackに通知するアプリを作ってみた～後編～

この記事は[ニフティグループ Advent Calendar 2021](https://qiita.com/advent-calendar/2021/nifty)の9日目です。

# はじめに
この記事は[前編](https://qiita.com/sakauchi_riki/private/3194e6ae2fdb7916784a)の続きとなっています。まだこちらを読んでいない方はこちらの記事から読むことをオススメします。

みなさま初めまして。社会人1年目の仲上といいます。今回は、前編の坂内と協力して1つのテーマを書きあげました。2記事で1つのテーマなので少々長いですが、読んでいただけると幸いです。
ということで、さっそく本題に進もうと思います。

# 全体図
[前編](https://qiita.com/sakauchi_riki/private/3194e6ae2fdb7916784a)でも上げましたが、最終的に出来上がるものの全体図です。後編では赤丸で囲まれた部分の実装を行っていきたいと思います。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1586001/c317516c-72e4-ebf8-91d8-65b6778656f4.png" width=50%>

# 下準備
今回の実装で必要なライブラリの導入やトークンの発行などを行います。

## 1.SlackAppライブラリの導入
今回はSlackにメッセージを送信するため、SlackAppライブラリを使用します。導入するときは以下のIDを登録します（登録方法は[前編](https://qiita.com/sakauchi_riki/private/3194e6ae2fdb7916784a)に書いてあるので、そちらを参考にしてください）

- ID:1on93YOYfSmV92R5q59NpKmsyWIQD8qnoLYk-gkQBI92C58SPyA2x1-bq

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1586001/32a7ea2c-d17a-81c3-6d83-6107d3f05d17.png" width=50%>


参考:[Slack BotをGASでいい感じで書くためのライブラリを作った](https://qiita.com/soundTricker/items/43267609a870fc9c7453)

## 2.Slackアプリ用トークンの発行
Slackにメッセージを送信するためには、Slack側からSlackApp用のトークンを発行する必要があります。この時気を付けなければならないのが、SlackAppのスコープです。スコープはSlackAppにおけるアクセス権限を設定する項目です。
適切なスコープを付与しないと、権限不足でメッセージが送信できないなんてこともあります。逆につけすぎると、トークンが漏洩した際の不正アクセスリスクが高まるので、必要最低限のトークンを付けてあげましょう。
今回は以下のスコープを付与しています。トークンの発行手順については、参考リンクを参照してください。

- chat:write
- chat:write.customize
- chat:write.public

参考:[【2021年版】GASとSlack APIでボットを作成しチャンネルにメッセージを自動投稿する方法 | AutoWorker〜Google Apps Script(GAS)とSikuliで始める業務改善入門](https://auto-worker.com/blog/?p=2904)

# 関数ごとに解説
## 最新ニュースのURLをプロパティに格納する関数
```javascript:setProperty.gs
/**
 * 最新のニュースURLをプロパティに格納する
 * @param {String} ニュースのURL
 * @return {boolean} URLがプロパティの値と異なるかどうか
 */
function setProperty(newsUrl) {
  //URLがプロパティの値と異なる場合、プロパティの値をURLで上書きしtrueを返す
  if (newsUrl != PropertiesService.getScriptProperties().getProperty("LATEST_NEWS_URL")) {
    //スクリプトプロパティで「LATEST_NEWS_URL」キーに値を格納する
    PropertiesService.getScriptProperties().setProperty("LATEST_NEWS_URL", newsUrl);
    //スクリプトプロパティを出力する
    Logger.log("「" + PropertiesService.getScriptProperties().getProperty("LATEST_NEWS_URL") + "」をプロパティに格納しました");
    return true
  }
  //プロパティの値と同じ場合、falseを返す
  else{
        Logger.log("${newsUrl}はすでにプロパティに登録されています");
    return false
  }
}
```
- Slackに送信したURLをGASのプロパティに記憶します
- 新たに取得したURLがプロパティの値と異なる場合はプロパティの値を上書きしてtrueを返す、プロパティの値と同じならfalseを返すようになっています。
- `PropertiesService.getScriptProperties().getProperty("キー")`でプロパティの値を呼び出しています
- `PropertiesService.getScriptProperties().setProperty("キー", 値)`でプロパティに値を格納しています

### GASのプロパティについて
今回はスクリプトが終了しても送信したURL情報を保持していたかったので、GASのプロパティ機能を用いています。
> スクリプトプロパティは、keyとvalueの一対でデータを保管することができます。その後、スクリプトプロパティでkeyを指定することで保存しておいた値を呼び出すことが可能です。
参考:[GASのスクリプトプロパティをコードで設定する方法(setPropertyメソッド)](https://auto-worker.com/blog/?p=2365)

今回は引き継ぎたい値が１つだけだったためプロパティを用いましたが、配列などの値のを格納したい場合や後からどんどん付け足していきたい場合はスプレッドシートに保存するというやり方も考えられます。


## Slackにメッセージを送信する関数
```javascript:postSlack.gs
/**
 * 引数の文字列を特定のチャンネルにポストする
 * @param {String} 送信したいメッセージ
 */
function postSlack(message) {
  //SlackAPIで登録したボットのトークンを設定する
  const token = "xxxx-xxxxxxxxxxxx-xxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxx"; //ここに取得したトークンを貼る
  //ライブラリから導入したSlackAppを定義し、トークンを設定する
  const slackApp = SlackApp.create(token);
  //Slackボットがメッセージを投稿するチャンネルを定義する
  const channelId = "#xxxxxxxx"; //ここに投稿したいチャンネル名を書く

  //SlackAppオブジェクトのpostMessageメソッドでボット投稿を行う
  slackApp.postMessage(channelId, message);
}
```
- Slackにメッセージを送信するための関数
- SlackAppライブラリを使用
- 使うときはtokenに自分が発行したトークンを入れ、```channnelId```に投稿したいチャンネル名を入れてください。

## main関数

``` javascript:main.gs
function main() {
  // ニフティニューストップのURLで初期化する
  const niftyNewsUrl = "https://news.nifty.com/";
  // ニフティニュースのHTMLを取得する
  const niftyNewsHtml = urlToHtml(niftyNewsUrl);
  // ニフティニュースのhtmlから注目ニュースのURLを取得する
  const topUrl = getTopNews(niftyNewsHtml);
  // 注目ニュースのURLが前回送信したものと異なる場合、SlackにURLを送信する
  if (setProperty(topUrl)) {
    postSlack(topUrl);
  }
}
```
この関数ををGASのトリガーを使って一定時間ごとに動すことにより主要ニュースの記事URLをとってくることができます。
実行頻度はひとまず１時間おきに設定してます。(あまり頻度が高すぎると、サイトからアクセス制限を受けてしまうかもしれないので)

### GASのトリガー
GASではスクリプトを実行するためのトリガーを設定することができます。トリガーの種類は様々で、一定時間おき・曜日指定・時間指定などがあります。今回は１時間おきに実行するように設定しました。
#### 設定方法
トリガーの設定は下の画像に示した部分から設定することができます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1586001/813759d8-be2f-fa99-383e-6365cd7cdde8.png" width=50%>

右下にある「トリガーを追加」ボタンを押すと設定画面が表示されます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1586001/113cfeba-0415-cc5b-810c-785151af6cd5.png" width=50%>

今回は下図のように設定しました。１時間おきにmain.gsが実行されます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1586001/5e2e145c-d284-d890-0835-062ec4413fbb.png" width=50%>

参考:[時限式のイベントトリガーを設置して決まった時刻にBotを送信する方法](https://tonari-it.com/gas-timed-driven-trigger/)

# 実行結果
こんな感じの通知が１時間おきにSlackメッセージが送信されます

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1586001/2ee15e3c-b25d-c0c0-94f5-1154d21297bb.png" width=175%>

# まとめ
後編では以下のことについて書きました。

- プロパティサービスを用いた変数の格納、取り出し
- Slackチャンネルにメッセージをポストする方法
- トリガーを用いた自動実行

GASはGoogleのサービスとの連携が強力なため、Gmailやスプレッドシートなどの処理を自動化することもできます。しかも、Googleアカウントがあれば使えてしまうというお手軽さ!(サーバーの準備やらクレジットカード登録などが全くいらない)
GASには今回紹介しきれていない機能や使い方がまだまだあるので、ぜひ一度使ってみてください。この記事がGASに触れるきっかけなどになれば幸いです。