自動化
PR

Slackに投稿されたメッセージを自動でスプレッドシートに転記する方法【GAS】

sanane
記事内に商品プロモーションを含む場合があります

はじめに

SANANE
SANANE

今回の記事では、Slack上の特定のチャンネルに投稿されたメッセージを自動でGoogleスプレッドシートに記録する方法を紹介します。

プロジェクトの管理や分析を目的として、Slack内のチャンネルのメッセージをスプレッドシートに記録したいと思ったことはないでしょうか?

今回はGoogle Apps Script(GAS)を使用して、自動化を実現します。

GASは30分ごとや1時間ごとなど、定期的に実行させることが可能なため、一度設定すればこれまでの手動でのメッセージのコピーやペースト、またはSlackからのエクスポート作業は不要になります。

動作イメージ

SANANE
SANANE

まずは簡単に本自動化処理の動作について説明します。

記録を行いたいSlackのチャンネル上でテスト投稿を行います。

記録用のスプレッドシートには以下のように記載が行われます。

投稿内容だけでなく、メッセージへの添付ファイルをGoogleドライブに保存するツールも紹介しております。コチラも合わせてご参考ください。

あわせて読みたい
Slackに投稿された添付ファイルを自動でGoogleドライブに保存し記録する【GAS】
Slackに投稿された添付ファイルを自動でGoogleドライブに保存し記録する【GAS】

作成方法

本自動化処理は以下の流れで作成します。

  1. Slack Appの作成
  2. Slack Appをチャンネルに追加する
  3. Googleスプレッドシートの作成
  4. GASの作成、定期実行トリガーの作成

Slack Appの作成

Slack APIにアクセスします。

このとき、自動化したいチャンネルがあるワークスペースでログインします。

[Create New App] をクリックし、[From scratch]をクリックします。

任意のアプリ名を入力、ワークスペースを選択し、 [Create App]をクリックします。

スコープの設定

左側のメニューより、[OAuth & Permissions]をクリックします。

[Scopes]セクションにて、下記画像のようにBot Token Scopesに以下3つをスコープとして[Add an OAuth Scope]をクリックして登録してください。

  • channels:history
  • channels:read
  • users:read

アプリをワークスペースにインストールする

スコープを設定した後、[OAuth & Permissions]の一番上のページにある[Install to Workspace]をクリックします。

権限をリクエストされるため、[許可する]をクリックします。

インストール完了後は、Bot User OAuth Token が生成されますのでコチラをコピーして控えておいてください。

Slack Appをチャンネルに追加する

Slackに移動し、今回の自動化処理を適用したいチャンネルに移動します。

メッセージ入力欄にて「/」と入力することでショートカットが開きます。

左メニューに新しくインストールしたAppがあることを確認し、[このチャンネルにアプリを追加する]をクリックします。

Googleスプレッドシートの作成

Googleスプレッドシートにアクセスします。

作成したスプレッドシートの拡張機能からApps Script をクリックします。

GASの作成

GASのスクリプトエディタが別タブで開きます。

スクリプトのペースト

もともと記載してある以下コードは削除します。

function myFunction() {

}

代わりに、以下のコードをコピーしてペーストします。

このとき、2〜3行目の各” ”で囲まれたところに控えておいたトークンやIDに書き換えます。

YOUR_SLACK_BOT_TOKEN:Bot User OAuth Token

YOUR_CHANNEL_ID:記録を行いたいSlackのチャンネルのID

あわせて読みたい
Slack チャンネルIDの探し方
Slack チャンネルIDの探し方
function saveMessagesToSheet() {
  const token = "YOUR_SLACK_BOT_TOKEN";
  const channel = "YOUR_CHANNEL_ID";
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];

  // ヘッダーの設定
  if (sheet.getRange("A3").getValue() === "") {
    sheet.getRange("A3").setValue("投稿時刻");
    sheet.getRange("B3").setValue("投稿者");
    sheet.getRange("C3").setValue("投稿内容");
  }

  const lastExecutionTime = new Date(sheet.getRange("A1").getValue());
  const apiUrl = `https://slack.com/api/conversations.history?channel=${channel}&limit=100`;
  const options = {
    method: "get",
    headers: {
      "Authorization": `Bearer ${token}`
    }
  };

  const response = UrlFetchApp.fetch(apiUrl, options);
  const data = JSON.parse(response.getContentText());

  for (let i = 0; i < data.messages.length; i++) {
    const message = data.messages[i];
    processMessage(message, token, sheet, lastExecutionTime);

    // スレッドの返信がある場合
    if (message.reply_count > 0) {
      const repliesApiUrl = `https://slack.com/api/conversations.replies?channel=${channel}&ts=${message.ts}`;
      const repliesResponse = UrlFetchApp.fetch(repliesApiUrl, options);
      const repliesData = JSON.parse(repliesResponse.getContentText());

      for (let j = 0; j < repliesData.messages.length; j++) {
        processMessage(repliesData.messages[j], token, sheet, lastExecutionTime);
      }
    }
  }

  // 最終実行時刻の更新(JST)
  const currentTimeJST = Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "yyyy-MM-dd HH:mm:ss");
  sheet.getRange("A1").setValue(currentTimeJST);
}

function processMessage(message, token, sheet, lastExecutionTime) {
  const messageTimestamp = new Date(message.ts * 1000);

  if (messageTimestamp > lastExecutionTime) {
    const userApiUrl = `https://slack.com/api/users.info?user=${message.user}`;
    const userResponse = UrlFetchApp.fetch(userApiUrl, {
      method: "get",
      headers: {
        "Authorization": `Bearer ${token}`
      }
    });

    const userData = JSON.parse(userResponse.getContentText());
    const userName = userData.user ? userData.user.real_name : "Unknown User";

    const nextRow = sheet.getLastRow() + 1;
    sheet.getRange(nextRow, 1).setValue(messageTimestamp);
    sheet.getRange(nextRow, 2).setValue(userName);
    sheet.getRange(nextRow, 3).setValue(message.text);
  }
}

上部メニューの[プロジェクトを保存]ボタンをクリックして保存します。

トリガーの作成

SANANE
SANANE

最後に定期的に実行するためのトリガーを作成します。

GASスクリプトエディタの左部のメニューから「トリガー」(時計のアイコン)をクリックし、画面下部の「+ トリガーを追加」をクリックします。

実行する関数を[saveMessagesToSheet]に設定し、イベントソースを[時間主導型]に、時間ベースのタイマーのトリガーのタイプを選択では[時間ベースのタイマー]に設定します。

時間の間隔を選択では[1時間おき]等、実行したい間隔を選択して保存をクリックします。

補足

トリガー保存時にエラーが発生した場合は、スクリプトがうまく保存されていない場合がありますので、再度コードを書く画面に戻ってブラウザの更新をしてください。

その後再度スクリプトをコピー&修正してください。

最初の関数の実行には権限が必要となるため、[承認が必要です]というモーダルが表示されたら、

  1. [権限を確認]をクリック
  2. [表示されているGoogleアカウント(Choose an account)]をクリック
  3. [詳細(Advanced)]をクリック
  4. [Go to 無題のプロジェクト(unsafe)]をクリック
  5. [許可(Allow)]をクリック

詳細については以下の記事を参考にしてください。

あわせて読みたい
Google Apps Scriptで「承認が必要です」が表示されたときの対応方法について解説【GAS】
Google Apps Scriptで「承認が必要です」が表示されたときの対応方法について解説【GAS】

クリック後トリガーが作成されます。

動作テスト

GASの左部のメニューから「エディタ」をクリックします。

[▶実行]をクリックします。

問題なく実行が完了すると、作成したスプレッドシートのA1セルに実行した時間が記録され、直近100件のメッセージが記録されます。

以降はトリガーに設定した時間ごとにGASが実行され、A1セルに記載された最終実行時間以降に投稿されたメッセージを記録します。

初回の実行では直近100件のメッセージを取得しますが、最大1000件まで過去のメッセージを取得するようカスタマイズすることができます。

この場合はスクリプトの14行目の[“&limit=100”]の[100]を任意の値に修正してください。

GASおすすめ本

GASをもっと勉強したい!ほかにも自分で何か作成したい!という方には以下がおすすめです。仕事で使えるアイデアなども得ることができます。

ABOUT ME
さなね
さなね
システムエンジニアとしての傍ら、自動化に関するツールの作成や発信をしています。 ココナラで紹介しているツールのカスタマイズを承っています。
記事URLをコピーしました