Slack APIでチャンネルのメッセージを取り出してみる

Webの初心者です。さらに?Qiita初投稿です。
Slack APIを使ってチャンネル内のメッセージ(会話)を取り出す、というのをやってみたので、そのときの手順を書きます。ほかの初心者の方の参考になれば幸いです。


まずはテスト用のワークスペースを作成。convhist(conversation history)という名前をつけました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314827/98bec8d6-0c26-8434-72cf-b75c05919e5b.png)


このワークスペース内にapitestというチャンネルを作成。このチャンネルのメッセージ(会話)をSlack APIで取り出すことを目標とします。

1. Slack Appの作成(API受付準備)
2. 使用するAPI



## 1. Slack Appの作成(API受付準備)

"App"とあるのでWebサーバー上にアプリを作るのかと思ったのですが、アプリというよりはむしろワークスペースに参加できる架空のユーザーを作成する感じです。普通のユーザー(人)がSlack画面から操作するのに対し、AppはAPI経由でアクセスする、というイメージです。

APIを使うには、Appの作成 → トークン取得 → APIに必要なスコープの設定、となります。 

### Appの作成
Appは以下のWebサイトから作成します。Appの作成手順はいくつかのサイトで詳しく書かれているので割愛します。
https://api.slack.com/
このページで、Your Apps > Create New App で、[Create a Slack App] ダイアログがでてきます。
[Create a Slack App]ダイアログにてAppNameを決めます。
**App Name**: GetConvHist (なんでもいい)
**Develpment Slack Workspace**: convhist (上記のワークスペース名)

このAppに対する情報設定画面が表示されます。ここでトークン取得およびスコープ設定が必要になります。最低でも一つのスコープを設定(追加)しないとトークンが得られないようです。

### ユーザーのトークンとボットのトークン
Appがワークスペースにアクセスするとき、あるときはボットとして、またあるときは自分(App作成者)の代行として振る舞うことができます。どちらで振る舞うかは、APIを実行するときにつかうトークンによって区別されます。

### APIに必要なスコープ
Appには、許される操作の範囲を設定する必要があります。許される操作の範囲は"スコープ"と呼ばれるものでカテゴライズされています。ボットとして振る舞うとき、自分(App作成者)の代行として振る舞うときそれぞれに対し、あらかじめ(APIを実行する前に)スコープが設定されている必要があります。

左側のメニューリスト > OAuth & Permissions を選択。
今回は自分(App作成者)の代行として振る舞うことにして、User Token Scopes にスコープを追加します。チャンネルのメッセージを取得するのが目的なので、conversation list と conversation history(後述します) に必要な以下のスコープを追加します。
channels:history
channels:read
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314827/2a0bc4fc-7f81-8f02-e58c-58a4210755bd.png)


追加したら、その画面の一番上のほうにあるOAuth Tokens & Redirect URLs で、[Install App to Workspace]ボタンを押します。Appがワークスペースにアクセスする権限を[許可]します。すると、OAuth Access Token が得られます。このトークンはAPIを投げるときに使います。ちなみにスコープ設定変更のたびにAppの再インストールが必要です。再インストールといってもこのページ上の画面の操作で済むようになっており、下の添付画面ではボタンが[Reinstall App]になっています。再インストールしてもトークン文字列自体は変わりません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314827/a3bb7ad5-0012-e9dd-e210-01df5971e262.png)


もしAppをボットとして振る舞わせたいのなら、Bot Token Scopesにのほうにスコープを追加し、Bot User OAuth Access Token を取得し、APIを投げるときにはそちらのトークンを使います。

これで、ワークスペースがAppからのAPIを受け付けるようになります。

## 2. 使用するAPIメソッド
Slackの提供する大量のAPIメソッドから、目的のものを探します。チャンネルの情報を取得したいので、channels.???でしょうか？　channels.historyというメソッドがあったので、ここからスタートです。まずは[APIメソッドのドキュメント](https://api.slack.com/methods)を見ると、channels.historyはすでに非推奨になっており、**conversations.history**を使え、とあります。
[conversations.history](https://api.slack.com/methods/conversations.history)のページを見ると、メソッドの仕様や必要なスコープが記載されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314827/7459c94e-ecd1-1305-ceb7-a95cf5226a4b.png)
ユーザートークンでconverstion.historyを使うには、channels:history, groups:hisotry, im:history, mpim:historyが必要となっています。実際には全部必要なわけではなく、操作対象に対応するもの、例えばpublicのチャンネルにアクセスするにはchannels:historyだけでよいようです。
conversations.historyの引数の説明を見てみると、tokenとchannelの２つがRequiredになっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314827/b7ead83b-c562-999a-3bb4-25d53c6e1f43.png)

APIメソッドドキュメントのページにはTesterというタブがあり、ありがたいことにお試し実行できるようになっています。いまはapitestというチャンネルの情報を取りたいので、試しに、tokenには上記のOAuth Access Tokenを入力、channelに#apitestと入力して実行してみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314827/8c63a87a-50d0-306b-35f5-8d2d4efdd5d1.png)
送信文字列とレスポンスが見れるようになっています。・・・channel_not_found。失敗しているようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314827/eae26c59-bcfc-296c-6bed-f5633da0c49e.png)

改めて引数を確認すると、channel には Conversation ID なるものを使うことになっています。Conversation IDが何なのかを正当な?手段で調べてはいませんが、conversations.createやconversations.list のレスポンスにid という値があり、これを指すものと思われます。

conversations.listのページのTesterで実行し、そのレスポンスを見ると、apitestというチャンネルに"CTEE1LMQT"というidが割り当てられています。

```
"ok": true,
"channels": [
    {
        "id": "CTEE1LMQT",
        "name": "apitest",
        "is_channel": true,
```

conversations.historyのページに戻りTesterでこのidを使って実行すると、今度は成功です。

実際にメッセージを取れるのか確認です。Slackの普通の操作画面で、チャンネルapitestに「helloあいう」というメッセージを送信。この状態でconversations.historyを実行すると、以下のようなレスポンスになっています。最新のメッセージがレスポンスの先頭になるようです。

```
"ok": true,
"messages": [
    {
        "client_msg_id": "edc34a1f-6e19-47fe-864d-af762c939934",
        "type": "message",
        "text": "hello\u3042\u3044\u3046",
        "user": "UTRUE3W13",
        "ts": "1581446370.000500",
```

tsはunixtimeのtimestampのようです。メッセージの初回の送信の時刻が維持され、編集しても変わりません。さきほどの「helloあいう」を編集して「helloあいうえお」にするとeditというノードが作成され、そこにまたtsが現れます。

```
        "ts": "1581446370.000500",　← これは変わらない
        "edited": {
            "user": "UTRUE3W13",
            "ts": "1581446760.000000" ← 編集時刻
        },
```


### API送信の確認
検索して最初に目についたpython slackclientを使ってみました。slackclientのドキュメントは[ここ](https://github.com/slackapi/python-slackclient)です。
メッセージごとにテキストのみを取り出しファイルに書き込むという簡単なコードです。

```Python
import slack

token_str = {OAuth Access Token}
client = slack.WebClient(token=token_str)

response = client.conversations_history(channel="CTEE1LMQT")

for res in response["messages"]:
    print(res['user'])
    print(res['ts'])
    if ('edited' in res):
        print('edited_ts='+res['edited']['ts'])
    with open(f"./slack/{res['user']}_{res['ts']}", "w") as f:
        f.write(res['text'])
```

以上、すこしでも参考になれば幸いです。