3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

asyncio アプリ内から Slack にメッセージを投稿しよう

Last updated at Posted at 2022-01-18

Python で Slack API や Webhook を扱うなら公式 SDK(slack-sdk/slack-bolt)を使おう」シリーズの記事です。公式 SDK についての概要、他にも記事がリンクされていますので、こちらのエントリーページにもアクセスしてみてください。

Slack 公式 SDK の asyncio サポート

このページに辿り着いたということは asyncio を活用してアプリケーション開発をされていますか?

Slack 公式 SDK である slack-sdkAIOHTTP を HTTP クライアントとして利用する形で asyncio をサポートしています。

この記事ではそのモジュールの使用方法をコード例とともに紹介していきます。

なお、こちらの記事は「Slack Python SDK でチャンネルにメッセージを投稿しよう」という記事をベースにしています。もし asyncio ではない一般的な Python コードの例を探している場合は、そちらの記事を参考にしてください。

AIOHTTP を使ってチャンネルにメッセージを投稿する

この記事では slack-sdk PyPI パッケージを使って Slack のチャンネル、DM にメッセージを投稿するコーディングについて解説します。以下の内容を説明していきます。

  • chat.postMessage API でメッセージを投稿
  • Incoming Webhooks でメッセージを投稿
  • メッセージを更新・削除
  • エフェメラルメッセージを投稿
  • ユーザーインタラクションに対して返信

盛りだくさんになっていますが、いきなりすべてを理解する必要はありませんので、必要になったときにこの記事を読み返してみてください。

chat.postMessage API でメッセージを投稿

それでは早速 chat.postMessage API の使い方から始めていきましょう。まずこの API を使うためには chat:write という OAuth スコープが必要となります。この権限を持つアプリの設定は以下のようになります。早速、こちらのリンクから作成してみてください。

_metadata:
  major_version: 1
  minor_version: 1
display_information:
  name: chat.postMessage App
features:
  app_home:
    messages_tab_enabled: true
    messages_tab_read_only_enabled: false
  bot_user:
    display_name: chat.postMessage Bot
oauth_config:
  scopes:
    bot:
      - chat:write
      # この記事では詳細を解説しませんが、この権限があれば bot user は public チャンネルに限り、チャンネルに参加せずにメッセージを投稿できるようになります
      - chat:write.public
      # この記事では詳細を解説しませんが、アプリからの投稿ではありますが username / icon_emoji / icon_url を変更して見た目を変えることができるようになります
      - chat:write.customize

作成できたら「Install to Workspace」ボタンから Slack ワークスペースにインストールすると Settings > Install App のページ内の「Bot User OAuth Token」という名前で xoxb- で始まるトークンが発行されているかと思います。これを SLACK_BOT_TOKEN という名前で環境変数に設定しておいてください。

export SLACK_BOT_TOKEN=xoxb-111-222-xxxx

以上で、この記事のサンプルを動かすための Slack アプリの設定は完了です。Python プロジェクトを設定してコードを実行していきましょう。

この記事のコードは全て Python 3.6 以上で動作します。python3 --version でバージョンを確認してください。この記事では Poetry を使って説明していきます。インストールしていない人はこちらを参考にしてください。

それではプロジェクトを作っていきましょう。

# 新しいプロジェクトを作成
poetry new chat_postMessage_app
cd chat_postMessage_app/

# 必要に応じて poetry env use 3.9 など

# virtualenv を有効化
poetry shell

# slack-sdk と aiohttp を追加
poetry add slack-sdk aiohttp

requirements.txt であれば

slack-sdk>=3.13,<4
aiohttp>=3.7.3,<4

のようにしてください(バージョンは使用したいものに合わせてください)。

asyncio は Python の標準モジュールですが、slack-sdk が利用する aiohttp はあくまで広く利用されている 3rd party ライブラリです。slack-sdk をインストールするだけでは aiohttp は追加されませんので、必ず明にインストールするようにしてください。これでひとまず完了です。

とりあえず投稿してみる

まずはボットユーザーとしてメッセージを投稿してみましょう。以下のソースコードを bot.py として保存してください。

import asyncio, logging, os

# デバッグレベルのログを出力します
logging.basicConfig(level=logging.DEBUG)

from slack_sdk.web.async_client import AsyncWebClient
from slack_sdk.errors import SlackApiError

# Web API クライアントを初期化します
client = AsyncWebClient(os.environ["SLACK_BOT_TOKEN"])

async def main():
    try:
        # chat.postMessage API を呼び出します
        # メソッド呼び出しに await キーワードをつけるのを忘れずに!
        response = await client.chat_postMessage(
            channel="#random",
            text=":wave: こんにちは!",
        )
        print(response)
    except SlackApiError as e:
        assert e.response["ok"] is False
        assert e.response["error"]  # str like 'invalid_auth', 'channel_not_found'
        print(f"Got an error: {e.response['error']}")

# asyncio.run は簡単に async 関数を実行するためのユーティリティです
asyncio.run(main())

実行が成功すると以下のような出力になるはずです。

(.venv) bash-3.2$ export SLACK_BOT_TOKEN=xoxb-111-222-xxx

(.venv) bash-3.2$ python bot.py
DEBUG:slack_sdk.web.base_client:Sending a request - url: https://www.slack.com/api/chat.postMessage, query_params: {}, body_params: {}, files: {}, json_body: {'text': ':wave: こんにちは!', 'channel': '#random'}, headers: {'Content-Type': 'application/json;charset=utf-8', 'Authorization': '(redacted)', 'User-Agent': 'Python/3.9.1 slackclient/3.5.1 Darwin/20.4.0'}
DEBUG:slack_sdk.web.slack_response:Received the following response - status: 200, headers: { ... }, body: {'ok': True, 'channel': 'C111', 'ts': '1622017093.007700', 'message': {'bot_id': 'B111', 'type': 'message', 'text': ':wave: こんにちは!', 'user': 'U111', 'ts': '1622017093.007700', 'team': 'T111', 'bot_profile': {'id': 'B111', 'deleted': False, 'name': 'chat.postMessage App', 'updated': 1622016343, 'app_id': 'A111', 'icons': {'image_36': 'https://a.slack-edge.com/111/img/plugins/app/bot_36.png', 'image_48': 'https://a.slack-edge.com/111/img/plugins/app/bot_48.png', 'image_72': 'https://a.slack-edge.com/111/img/plugins/app/service_72.png'}, 'team_id': 'T111'}}}

そして Slack ワークスペースの #random チャンネルに以下のようなメッセージが投稿されているはずです!

うまくいきましたか?おめでとうございます :tada:

ユーザーに成り代わっての投稿や blocksattachments の利用方法など、WebClient と何ら関わるところはありません。それらについてはこちらの記事を参考にしてください。

Incoming Webhooks でメッセージを投稿

基本的にはこちらの記事と同様なのですが、コード例が異なりますので、最初のコード例のみこちらに載せておきます。そこからのカスタマイズは特に変わるところはありません。

import asyncio, logging, os

# デバッグレベルのログを出力します
logging.basicConfig(level=logging.DEBUG)

# Web API クライアントを初期化します
from slack_sdk.webhook.async_client import AsyncWebhookClient
client = AsyncWebhookClient(os.environ["SLACK_WEBHOOK_URL"])

async def main():
    # メッセージを送信します
    # メソッド呼び出しに await キーワードをつけるのを忘れずに!
    response = await client.send(text=":wave: こんにちは!")
    print(f"status: {response.status_code} body: {response.body}")

# asyncio.run は簡単に async 関数を実行するためのユーティリティです
asyncio.run(main())

メッセージを更新・削除

それでは API を使ってメッセージの更新・削除もやってみましょう。

import asyncio, logging, os

# デバッグレベルのログを出力します
logging.basicConfig(level=logging.DEBUG)

# Web API クライアントを初期化します
from slack_sdk.web.async_client import AsyncWebClient
client = AsyncWebClient(os.environ["SLACK_BOT_TOKEN"])

async def main():
    # 新しいメッセージを投稿 (await を忘れずに!)
    new_message = await client.chat_postMessage(
        channel="#random",
        text=":wave: こんにちは!",
    )

    # わかりやすくするために sleep
    await asyncio.sleep(2)

    # 自分が投稿したメッセージを更新
    await client.chat_update(
        channel=new_message["channel"],
        ts=new_message["ts"],
        text=":wave: こんばんは!",
    )

    # わかりやすくするために sleep
    await asyncio.sleep(2)

    # 自分が投稿したメッセージを削除
    await client.chat_delete(
        channel=new_message["channel"],
        ts=new_message["ts"],
    )

# asyncio.run は簡単に async 関数を実行するためのユーティリティです
asyncio.run(main())

Slack チャンネル内での動作は以下のようになります。

エフェメラルメッセージを投稿

「エフェメラルメッセージ」とは、チャンネル内に投稿されていても特定のユーザーにだけ見えているメッセージです。Slack の画面上で「あなただけに表示されています(英語だと Only visible to you)」と表示されているメッセージを見たことがあるかもしれません。このメッセージは例えばスラッシュコマンドを実行したユーザーだけに「受け付けました!」のようなメッセージを表示したいときなどに便利です。では、このメッセージを API を使って送信してみましょう。

import asyncio, logging, os

# デバッグレベルのログを出力します
logging.basicConfig(level=logging.DEBUG)

# Web API クライアントを初期化します
from slack_sdk.web.async_client import AsyncWebClient
client = AsyncWebClient(os.environ["SLACK_BOT_TOKEN"])

async def main():
    # TODO: 実際のユーザー ID に変更してください
    user_id = "U03E94MK0"

    # 場所として channel を指定、誰に対して表示するかで user を指定します
    response = await client.chat_postEphemeral(
        channel="#random",
        user=user_id,
        text=":wave: あなただけにお知らせです!",
    )

# asyncio.run は簡単に async 関数を実行するためのユーティリティです
asyncio.run(main())

以下のようなメッセージが表示されたでしょうか?

割愛しますが、もちろん blocks も問題なく使えます。

ユーザーインタラクションに対して返信

スラッシュコマンド、ショートカットなどへの応答でメッセージを返信したいという方は、ぜひこちらの response_url に関する詳細な記事を参考にしてみてください。response_url への HTTP リクエストには AsyncWebhookClient を使うことができます。

まとめ

この記事では Slack API を使ってチャットにメッセージを投稿する方法について公式 Python SDK の asyncio 互換のコード例とともに網羅的に紹介しました。

繰り返しとなりますが、こちらの記事は「Slack Python SDK でチャンネルにメッセージを投稿しよう」という記事をベースにしています。もし asyncio ではない一般的な Python コードの例を探している場合は、そちらの記事を参考にしてください。

それでは :wave:

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?