カスタマーコンサルティングチームの谷口 翔です。
今回はSlack SDKを用いてTreasure Data CDPに蓄積されたデータを可視化、Slackに投稿することで定期的なチェックを行う体制を構築していきます。都度プログラムを実行することなく誰もが見られる場所で気軽にデータを確認できることが日々の変化への気づきに繋がっていくかと思います。今回は以下のステップで進めていきます。
- Slackでアプリケーションを登録しTokenを払い出す
- Treasure Data CDPのAPIキーと1で払い出したSlackのTokenを環境変数に保管する
- Slackへの投稿コードを作成する
前回の振り返り
前回は、以下の内容でTreasure Data CDPに蓄積されているデータを可視化していきました。
- pytdを使用してTreasure Data CDPからデータを抽出
- pandasによるデータの加工
- seabornによるチャート描画
対象者
- Treasure Data CDPでデータの蓄積がある程度完了している
- クエリの実行結果を都度ダウンロードし、Excelやスプレッドシートでチャートや集計表を作成していて工数がかかっている
- BIツールの導入・運用はコスト面で時期尚早だと感じている
- 社内コミュニケーションにSlackを導入している
Slack SDKとは
ビジネスチャットツールの一つであるSlackではbot等のアプリケーションを構築するためのAPIが公式で提供されています。Slackにメッセージを投稿する・取得する、チャンネルを作成する等のAPIが用意されていますが、それぞれのAPIを使用するために個別のプログラムを書く手間を下げるための公式SDKがSlackから提供されています。
SDKを使うことでPythonで簡単にSlackアプリケーションを構築することができます。またTokenを用いたWebAPI接続が廃止されたということもあり、そういった意味でもSlack SDKを用いてプログラムを構築することが推奨されています。
環境変数とは
環境変数とは、シェルから起動されたすべてのプロセスに有効な変数のことです。これだとなんのことかイメージが湧きづらいので今回の記事と関係する点を挙げると、Treasure Data CDPに外部から接続するためのAPI KeyやSlackに接続するためのTokenなどが関係してきます。
上記のような漏洩することが大きな問題になるキー等について、プログラムに直接記述するのではなく環境変数に保存し必要に応じて呼び出すことでセキュリティを高めることができます。今回の実行環境はMac OSのため、Terminalから~/.zshrcにSlack Tokenを書き込んでいます。
実行環境について
- Mac OS 11.5.2
- Python 3.9
- pytd 1.4.0
- pandas 1.3.4
- matplotlib 3.4.3
- seaborn 0.11.2
- slack-sdk 3.13.0
使用するデータについて
使用するデータについては前回の記事と同じものを使用しています。
Slackでのアプリの登録方法について
アプリケーションの作成
- Slack APIのYour Appsにアクセスし、Create New Appボタンを押します
- 作成方法を選択する画面が出ますが、From scratchを選択してください
- App Nameにアプリケーションの名前を設定(今回はPython_Image_Post)し、どのワークスペースに対して作成するかを選択し終えたら、Create Appボタンを押してください
アプリケーションの権限の設定
- 作成したアプリケーションの左側に並んでいる設定メニューから、OAuth & Permissionsを選択してください
- Scopesという項目でAdd an Oauth Scopeボタンを押します
- 表示される一覧から、『chat:write』と『files:write』を選択します
アクセストークンの取得
- 同じ設定画面の上部にあるInstall App to Workspaceボタンを押します
- アクセス権限を許可するかの画面が出るので、許可ボタンを押します
- Bot User OAuth Tokenの箇所にアクセストークンが発行されるのでコピーをします
チャンネルにアプリを登録する
- Slackでアプリ(bot)からメッセージを投稿したいチャンネルを表示します
- チャンネルの詳細からインテグレーションを選択します
- Appのアプリを追加するから、アプリケーションの作成で作成した『Python_Image_Post』を追加します
環境変数への書き込み
- 今回はMac OSが実行環境なので、まずターミナルを起動します
- zshrcファイルに書き込まれた環境変数が読み込まれるので、こちらに記述をします
- vim ~/.zshrcとコマンドを入れ編集画面を開きます
- 最終行に先ほど取得したSlackへのアクセストークンと前回確認したTreasure Data CDPへのAPIキーを以下のように書き込みます
※*(アスタリスク)を置き換えてください
※SLACK_BOT_TOKENがアクセストークンでSAMPLE_API_KEYがAPIキーですSLACK_BOT_TOKEN=****************************************************** SAMPLE_API_KEY=*********************************************
- ファイルを保存、終了しsource ~/.zshrcとコマンドを入れ、変数を反映した上でターミナルを終了します
作成したチャートをSlackに投稿するコード
基本的に前回使用したコードにSlackで投稿するコードを追記するだけですが、投稿する画像は一回保存する必要があるため、一旦25行目のsavefig()メソッドを使用して画像を保存しています。Slackに投稿するコード(try以降)については公式のコードを参考としているためエラー時の処理が記載されていますが、ここは必要に応じて省略したりエラー時の通知方法をメールにするなど適宜修正してください。
files_upload()メソッドの引数channelsで投稿したいチャンネルを、引数fileで投稿したい画像ファイルを、引数initial_commentで同時に投稿したいコメントを設定します。
※filepathとchannelsはご自身の環境に合わせて設定ください。
import pytd import pandas as pd import matplotlib.pyplot as plt import seaborn as sns import os from slack_sdk import WebClient from slack_sdk.errors import SlackApiError from datetime import datetime if __name__ == '__main__': now = datetime.now().strftime("%Y%m%d%H%M%S") client = pytd.Client(apikey=os.environ['SAMPLE_API_KEY'], endpoint='https://api.treasuredata.com/', database='sample_datasets', default_engine='presto') res = client.query('WITH t1 AS ( SELECT symbol ,TD_TIME_FORMAT(time,'yyyy','EST') as year ,MAX(time) as max FROM nasdaq WHERE symbol IN ('MSFT','ADBE') GROUP BY 1,2 ) SELECT nasdaq.symbol ,TD_TIME_FORMAT(nasdaq.time,'yyyy','EST') as year ,nasdaq.close FROM nasdaq INNER JOIN t1 ON nasdaq.symbol = t1.symbol AND nasdaq.time = t1.max ORDER BY 2,1 ') df = pd.DataFrame(**res) filepath = '*********************************' + now + '_chart.png' client = WebClient(token=os.environ['SLACK_BOT_TOKEN']) print(df.head()) sns.lineplot(x="year", y="close", hue="symbol", data=df) plt.xticks(rotation=90) plt.savefig(filepath) plt.show() try: response = client.files_upload( channels='#**********', file=filepath, initial_comment=(now+"_の画像")) assert response["file"] except SlackApiError as e: assert e.response["ok"] is False assert e.response["error"] print(f"Got an error: {e.response['error']}")
上記の設定に誤りがなければ、以下の様にSlackに画像が投稿されていると思います。
おわりに
普段から使用しているコミュニケーションツール(今回の場合はSlack)に自動で投稿されることで、作成者・閲覧者双方の負担を減らしつつ可視化結果を共有できることが確認できたかと思います。日々の変化を簡単に確認できることで、施策効果の確認や改善に繋げられるのではと思います。作成したコードを、Treasure Data CDP上のCustom Scriptや、各種IaaSサービスのインスタンスで実行することでメンテナンスも楽になるかと思います。
この記事が少しでも参考になりましたら幸いです。
商標
Slackは、Slack Technologies, Inc.の登録商標です。
参考書籍
小久保 奈都弥(2020)『データ分析者のためのPythonデータビジュアライゼーション入門 コードと連動してわかる可視化手法』翔泳社.
参考サイト
lis. “Slack API経由で投稿するbotを作る手順”. lisz-works. 2020-04-23. https://www.lisz-works.com/entry/get-slack-api