【GAS】#6 ブログにて発信しているユーザーを月毎に集計し、Slackへ通知する

1. 概要

Blog to Slack

本記事では「API連携」による通知について解説します。

2. SlackからWebHook URLを取得

2-1. Slackから「Add apps」をクリック

2-2. 「Incoming WebHooks」を検索し、「Add」ボタンをクリック

2-3. 「Add to Slack」をクリック

2-4. 「通知するチャンネルを選択」し、「Add Incoming WebHooks integration」ボタンをクリック後、「WebHook URL」(*6-3)を取得

  • 「https://hooks.slack.com/services/~」

3. サンプルコード

3-1. ファイル構成(GitHubで管理

  • notification/slack/scraping_blog_to_slack.gs
    • メインコード
  • notification/slack/gas_properties.gsheet
    • 「WebHook URL」を含め、コード内に書かない方が良いデータ(ID、PASSWORD、KEY等)をプロパティとして保存

3-2. スプレッドシートIDの取得

3-3. GAS Editorの開け方

※「+新規」をクリック

3-4. コード & 解説

※複数のプログラムよりプロパティファイルを共有する為、敢えてスタンドアロン型(*5-2)を採用する

// SlackのWebHook URLが記載されているスプレッドシートのID
const bookId = '1j2z-S●●●●●●●●●●●●●●●●●●●●●●●●●●●●cQk';
// Slackへ通知する際の名前
const username = 'Notification';

let ranking = new Map();

// Mainメソッド
// Blog記事一覧よりデータを取得&ランキングし、Slackへ通知
const main = () => {
  const targetUrl = getValueOfProperty('D20');
  const articles = scrapingBlog(targetUrl);

  const targetMonth = getTargetMonth(-1);
  const summary = getSummary(articles, targetMonth);
  const rankingTxt = sortRanking();
  const title = '先月の記事投稿ランキングです。';
  const desc = '■明細';
  sendToSlack(`${title}\n${rankingTxt}\n${desc}\n${summary}`);
}

// Blog記事一覧よりデータを取得
const scrapingBlog = (targetUrl) => {
  const html = getHtml(targetUrl);
  return Parser.data(html).from('<ol class="blog_list">').to('</ol>').build();
}

// サマリー
const getSummary = (articles, targetMonth) => {
  let summary = '';
  const timeTag = 'time';
  const aTag = 'a';
  const articleTitles = Parser.data(articles).from('<p class="title">').to('</p>').iterate();
  const articleDates = Parser.data(articles).from('<li class="date">').to('</li>').iterate();

  let idx = 0;
  articleDates.forEach((date) => {
    const dateValue = getValueInTag(date, timeTag);
    if (dateValue.indexOf(targetMonth) > -1) {
      const articleHtml = getHtml(getArticleLink(articleTitles[idx]));
      const authorName = Parser.data(articleHtml).from('<span id="authorName" class="authorName">').to('</span>').build();
      summary = `${summary}[${dateValue}]<${authorName}>${getValueInTag(articleTitles[idx], aTag)}\n`;
      // ランキング用のマップを設定
      if (ranking.has(authorName)) {
        ranking.set(authorName, ranking.get(authorName) + 1);
      } else {
        ranking.set(authorName, 1);
      }
    }
    idx++;
  });
  return summary;
}

// ランキングのソート
const sortRanking = () => {
  let rankingTxt = '';
  ranking = new Map([...ranking.entries()].sort((a, b) => a[1] < b[1] ? 1 : -1));
  ranking.forEach((value, key) => {
    rankingTxt = `${rankingTxt}●${key}さん:${value}件、ありがとうございます!\n`;
  });
  return rankingTxt;
}

// 対象月を取得
const getTargetMonth = (number) => {
  const now = new Date();
  now.setMonth(now.getMonth() + (number || 0));
  return Utilities.formatDate(now, 'JST', 'YYYY.MM');
}

// 対象URLからHTMLを取得
const getHtml = (targetUrl) => {
  const response = UrlFetchApp.fetch(targetUrl);
  return response.getContentText('UTF-8');
}

// タグ内の値を取得
const getValueInTag = (html, tag) => {
  const startIdx = html.indexOf('>') + 1;
  return html.substring(startIdx, html.length - tag.length - 3);
}

// Aタグのリンクを取得
const getArticleLink = (html) => {
  const href = '<a href="';
  const endIdx = html.indexOf('"', href.length);
  return html.substring(href.length, endIdx);
}

// 指定のスプレッドシートに記載されているプロパティの値を取得
const getValueOfProperty = (cell) => {
  const sheet = SpreadsheetApp.openById(bookId).getSheetByName('Properties');
  return sheet.getRange(cell).getValue();
}

// メッセージをSlackへ通知
const sendToSlack = (msg) => {
  const webhookUrl = getValueOfProperty('C20');

  // 通知する内容
  const param = {
    'username': username,
    'text': msg
  };
  // paramをJSON文字列に変換
  const payload = JSON.stringify(param);
  // APIを叩くにあたってどのような仕様で通信を行うか、どのような情報を送るかを指定
  const options = {
    'method': 'post',
    'headers': {
      'Content-Type': 'application/json'
    },
    'payload': payload
  };
  // APIの呼び出し(ここで実際に通知される)
  UrlFetchApp.fetch(webhookUrl, options);
}

4. 実行結果例

5. 参考

5-1. GAS(Google Apps Script)とは

5-2. 2種類の方式

5-3. Webhookとは

5-4. 「UrlFetchApp.fetch()」について

関連記事

  1. 【GAS】#1 Gmailに届いた新着メールをSlackに通知する

  2. 【GAS】#9 スプレッドシートの明日のシフト表より当番や時間を取得し…

  3. 【GAS】#10 ウェブアプリのフォーム入力からスプレッドシートへ記載…

  4. 【GAS】#8 TwitterのPublic Metricsデータを取…

  5. 【GAS】#2 Google Calendarに登録されている予定をS…

  6. 【GAS】#4 OCRにて画像からテキストを起こし、Lineへ通知する…