Qiitaの新着トレンドを見逃したくないので，Slackに記録するようにした

毎日欠かさずQiitaに来ては見ていますが，忙しかったりして見逃してしまうことがしばしばあるので，見逃してもいいようにSlackに記録するようにしました
~~だからといって，見るのを疎かにしてはいけない~~

# 利用した技術，ツールなど

* Google Apps Script(以下，GAS)
* Slack
    * Incoming Webhooks

# 基本的な流れ

1. GASでQiitaのトップページをスクレイピングします
2. newタグがついてる記事のURLと記事名をSlackのメッセージ形式に加工します
3. SlackのIncoming Webhooksを経由してSlackに記録します

# Slack

GASからのメッセージを受け取るため，Incoming Webhooksに新規に設定を追加します
Incoming WebhooksをまだSlackに導入してない方は[こちらから](https://slack.com/apps)導入してください
投稿時点だと，「Incoming」で一番上に表示されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56006/16fd3d97-8009-5557-2f07-e949dcc7eace.png)

追加すると，↓のように表示されるので，「設定を追加」から実際に設定を行います
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56006/9f26d4de-ff9e-6c32-14b6-c1480662ff33.png)


「設定を追加」を押すと，投稿先のチャンネルを設定する画面が出るので，適当なチャンネル名を設定してインテグレーションを追加します
このとき，Webhook URLが生成されますが，GASの方で使うのでどこかにコピペしておきます

Slackの設定は以上です

# GAS

GASファイルを作って，以下のソースをコピペします

```javascript

function doPost() {
  // Qiitaのトップページから取得
  var url = 'https://qiita.com/';
  var response = UrlFetchApp.fetch(url);
  var html = response.getContentText('UTF-8');

  // getTextでSlackに表示する文章を作成
  postSlack(getText(html));
}

// SlackのTextに設定する文字列を作成
function getText(html) {
  var text = '現在の新着トレンド記事\n';
  // 新着タグが付くときの条件
  var searchHtml = 'isNewArrival&quot;:true';
  var firstIndex = html.indexOf(searchHtml);
  var secondIndex = html.indexOf(searchHtml, firstIndex + 1)

  while(firstIndex != html.length) {
    // 新着タグから次の新着タグまでをごっそり抽出
    var str = html.substring(firstIndex, secondIndex);
    var itemUrl = getItemUrl(str);
    var itemName = getItemName(str);
    // Slackのtext部分を加工
    // <url|表示名>で，表示名にリンクを付与することができます
    text = text + '・<' + itemUrl + '|' + itemName + '>\n';

    // 新着タグのインデックスを更新
    var firstIndex = secondIndex;
    var secondIndex = html.indexOf(searchHtml, firstIndex + 1);

    // 一番最後の新着タグでマイナス(検索できなかった)は困るので，htmlの長さまでとする
    if (secondIndex == -1) {
      secondIndex = html.length;
    }
  }
  
  return text;
}

// ここから下のgetメソッド群は，&quot;でセパレートして，該当のインデックスを取得してます
function getUserId(str) {
  var searchHtml = '&quot;';
  var strs = str.split(searchHtml);
  return strs[28];
}

function getItemId(str) {
  var searchHtml = '&quot;';
  var strs = str.split(searchHtml);
  return strs[18];
}

function getItemName(str) {
  var searchHtml = '&quot;';
  var strs = str.split(searchHtml);
  return strs[14];
}

function getItemUrl(str) {
  return 'https://qiita.com/' + getUserId(str) + '/items/' + getItemId(str);
}

function postSlack(text) {
  var url = 'インテグレーションを追加したときに生成されたWebhook URL';
  var username = 'Slackに投稿するときのユーザー名';
  var jsonData = {
    "username": username,
    "text": text
  };
  
  var payload = JSON.stringify(jsonData);
  var options = {
    "method" : "post",
    "contentType" : "application/json",
    "payload" : payload
  };

  UrlFetchApp.fetch(url, options);
}
```

`doPost`メソッドを動かすと，SlackのIncoming Webhooksで設定したチャンネルに投稿されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56006/6bdf3d5d-e30d-799f-88a6-7c36217e4e19.png)

# GASの定期実行

このままでは，`doPost`は意図的に動かさないとSlackに投稿されないので，定期実行するように設定します
Qiitaの更新時刻は大体5:00と17:00なので，余裕を見て6:00と18:00に投稿するように設定します
GASの編集画面に↓のような時計のアイコンがありますが，ここから定期実行の設定を行えます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56006/bdf4ae30-4ee5-a858-6c18-1d7c809c7827.png)
クリックして開くと，「トリガーを作成」というボタンがあるので，そこからトリガーを追加します
設定する箇所は↓の黄色線を引いたところです
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56006/45f03f54-b622-e53d-3722-e49f1e2430b7.png)
↓のように設定を変更します

* 時間ベースのトリガーのタイプを選択を，「日付ベースのタイマー」に変更
* 時刻を選択を，「午前6時～7時」に変更(スクショでは時間の間隔を選択（時間）となってますが，日付ベースのタイマーに変更すると変わります)
* (GASの`doPost`のメソッド名を変えた方は)実行する関数を選択を，変えた後のメソッド名に変更

投稿日時では，まだこの動作確認はしていませんが，多分動きます(動いて問題なさそうなら，ここは変えておきます)

# 終わりに
* 超突貫工事で作成したので，特にスクレイピングした後の文字列加工はもうちょっといい感じにしたい・・・
    * というか，新着タグから新着タグまでぶっこ抜いているので，間に新着タグがついてない記事とかがあり，ちょっとした潜在バグ・・・
* とはいえ，Qiitaの新着トレンドは見逃しても大丈夫な状態になりました
    * 更に，記事の筆者名とリンクやタグの付与などができそうです
* ~~だからといって，見るのを疎かにしてはいけない~~
    * ~~大事なことかつ自戒を込めて，2回書きました~~


# 参考サイト
[Formatting messages | Slack](https://api.slack.com/docs/message-formatting)