見出し画像

Slackのポスト機能で毎週投稿していた日記をAPIで一括ダウンロードした話

ここ一年半、Slackのポスト機能を活用して、毎週やったこと・感じたことの振り返りを投稿していたのですが、今後使う環境やツールが変わっても閲覧できるように、手元にファイルとして残しておきたいと思ったのが今回の動機です。手動でやるには流石に量が多く、、、APIの活用に至りました。

大枠の流れ

流れとしては下記です。

  1. Slack Appを作成し、自分というユーザーと同じ権限をAPIに付与するためのOAuth Tokenを発行

  2. Python3のslack-sdkを通じた

    • a) 自分のユーザーIDの取得

    • b) 「#<チャンネル名>」から自分が投稿したポスト一覧の取得(各タイトル及びダウンロードリンク)

1. Slack Appを通じたOAuth Tokenの発行

ゴール:APIで使うために適切な権限が付与されたOAuth Tokenの発行

長らくプログラミングから離れており、Slack APIの活用が初めての自分としては、まずここでつまづきました。というのも、「普通にAPI叩きたいからTokenほしい」という頭になっているのですが、Slackではそのためにアプリと呼ばれるものを作成しなければならず、フローが分かりづらかったです。

(もともとそういったフローではなかったそうなのですが、2020年頃から「アプリ」という名称のもとAPIやBotなどを設定窓口を統一したらしい)

アプリの作り方はシンプル。https://api.slack.com/appsページに遷移し、「Create New App」➔「From an app manifest」➔ Workplaceを選択 ➔ JSON/YAMLはいじらず一旦作成するだけです。

すると、アプリが作成されそのアプリのページに飛ぶので、「Add features and functionality」から、このアプリが何をできるのかという機能を選択します。今回はBot等ではなくシンプルに「自分というユーザーが取れる行動をAPIでも可能にする」のが目的なので、右下の「Permissions」からAPI用のTokenを発行するだけです。

Permissionsページに移り、APIのScopesを設定します。Scopesには2種類存在し、Bot-Token ScopesとUser-Token Scopesがありますが、今回はUser-Token Scopesで下記3つを付与します。

  • search:read:Workplaceを検索する権限

  • files:read:ポスト機能は投稿にdocsファイルが添付されているのと同じ扱いになるので、ファイルを読む権限

  • users:read:自分の投稿に検索を絞り込むためにユーザーIDでフィルターする必要があり、自分のユーザーIDを特定するための権限

Scopesを設定したあとは、緑色の「Install to Workplace」ボタンを押して、このアプリをWorkplaceにインストールします。インストールといっても、Google CalendarやGithubのように、社員全員にアプリとして表示されるわけでは全くありません。あくまでWorkplaceと連携させるという意味でのインストールとなります。ちなみに、Scopesを編集した後は毎回Reinstallが必要なので、お忘れなく。

上記画面の「OAuth Tokens for Your Workplace」をコピーできれば、このステップは完了です。
試しに、こちらのAPIテストページでメッセージ検索に使ってみて下さい。

2. Pythonのslack_sdkの設定

下記のGithubレポジトリにあるSDKです。Python3.6以上の環境を構築し、
$ pip install slack_sdkでインストールしてください。(VS CodeのContainerでPython環境を設定すれば問題なく動きました)
slackclientという昔のライブラリの引き継ぎ先がこのSDKだそうです。

2.a 自分のユーザーIDの取得

あとはもう普通にSDKの関数を使って検索するという話なのですが、一つだけ注意点があります。検索するためのクエリは、SlackのWeb/デスクトップアプリケーションとそこまで変わらないのですが、投稿者を指定する「from:」キーワードの使い方がAPI/SDKでは異なります。
アプリケーションでは「from: @tanaka-taro」といった形でユーザー名でそのまま検索可能ですが、APIではこれができず、ユーザーIDで検索する必要があります。このユーザーIDを取得するために、今回はusers.lookupByEmail関数を使い、自分のユーザーIDを取得します。
https://api.slack.com/methods/users.lookupByEmail

from slack_sdk import WebClient

token = "上記で取得したxoxpから始まるUserToken"

client = WebClient(token=token)
response = client.users_lookupByEmail(email="myemail@mycompany.com")

2.b 自分が投稿したポスト一覧の取得

上記のユーザーIDが判明すれば、準備万端です。あとは、search_files関数を使って自分がアップロードしたポストのタイトルとダウンロード先を特定するだけです。

import os
import requests
from slack_sdk import WebClient

token = "上記で取得したxoxpから始まるUserToken"

client = WebClient(token=token)

# 検索し、結果をJSONオブジェクトを取得。デフォルトのcountが20なので、上限100に設定
response = client.search_files(query="from: <ユーザーID> in: <チャンネル名>", count=100)

files = [(item["url_private_download"], item["title"]) for item in response["files"]["matches"]]
print(len(files))

os.chdir("<任意のダウンロードフォルダー名>")

for item in files:
    print("url:", item[0], "\nTitle:", item[1])
    content = requests.get(
            item[0],
            allow_redirects=True,
            headers={'Authorization': 'Bearer %s' % token},
                        stream=True
        ).content
    
    content = content.decode("unicode-escape")
    with open(item[1], mode="w") as f:
        f.write(content)

細かな注意点としては、url_private_download先にあるファイルをダウンロードする際には、Token含め細かなheaderの設定をする必要があるということです。
また、ファイルは.txtではなく拡張子なしのバイナリファイル?的な感じでダウンロードされます。ポスト内の日本語は"\u"から始まるunicodeにエンコードされているので、decodeしてあげる必要もあります。

以上となります。

活用させていただいた文献


この記事が気に入ったらサポートをしてみませんか?