【仕事の自動化】手動で管理していない?|Slackチャンネル名の全部を一瞬で取得する方法

こんにちは、キノコードです。
Slackというチャットツールをご存知でしょうか?
最近ではリモートワークが進み、実際に業務でお使いの方も多いと思います。
この動画から数回に分けて、PythonでチャットツールSlackを便利に活用する方法を紹介します。
ちなみに、キノコードのコミュニティでもSlackを使用しています。
Slackを使用したことがある方は、こんな機能があればいいなと思ったことはないでしょうか。
例えば、チャンネルのデータを取得し、どのユーザーがたくさん発言しているかを表示させる機能。
毎日、同じ内容の文章を自動で送信できる機能などです。
これらを行うことができれば、業務の効率化につながるのではないでしょうか。
今回は、すべてのチャンネルの一覧データを取得する方法について説明します。
今後、Slackでの発言数取得などの分析に関する手法や、Slackでメッセージを自動配信する方法についても説明する予定です。
ぜひ最後までご視聴ください。
キノコードでは、この動画の他にも仕事の自動化の動画、株のデータ分析の動画なども配信しています。
チャンネル登録がまだの方は、新着通知が届きますので、チャンネル登録をお願いします。
それでは説明にうつります。

【仕事の自動化】手動で管理していない?|Slackチャンネル名の全部を一瞬で取得する方法

Slackについて

Slackとは、アメリカのSlack Technologies社が開発し、運営しているビジネスチャットツールです。
Slackは、管理者がワークスペースを作成し、そこにさまざまなチャンネルを作成することで、グループチャットや音声通話を行うことができます。
例えば、営業部メンバー用にワークスペースを作成し、プロジェクトごとにチャンネルを作成することができます。すると、プロジェクトに関わるメンバーだけが参加するチャットグループができることになります。

Slackを利用するときには、はじめにワークスペースを作成します。
今回は、テスト用に作成したこちらの「KinoVillageTest」というワークスペースを使用します。
では、ワークスペースについて説明します。
ワークスペースでは、チャンネルとダイレクトメッセージの二種類を利用することができます。
チャンネルには、さらに「パブリックチャンネル」と「プライベートチャンネル」があります。
「パブリックチャンネル」は、誰でも自由に参加・退出することができるチャンネルです。Slack上では、チャンネル名の左に「#」マークがついています。
「プライベートチャンネル」は、招待された人しか参加できないチャンネルです。招待されていないメンバーは、そのチャンネルの存在すら知ることができない仕組みになっています。 Slack上では、チャンネル名の左に鍵マークがついています。
ダイレクトメッセージとは、1対1から最大8名までメッセージができる機能です。
主に、チャンネル全体に知らせる必要のない、一度限りの会話をしたいときに便利な機能です。

今回使用する「KinoVillageTest」というワークスペースには、「alerts」「general」「random」「s」「proj-1」という5つのパブリックチャンネルがあります。

これらのパブリックチャンネルの全ての一覧を取得するものとします。
また、チャンネル一覧の取得と同時に、チャンネルそれぞれのトピックと説明も取得しましょう。

Slack APIとは

それでは、使用するAPIサービスのSlack APIに登録します。
APIとは、Webサービスやソフトウェアの機能を、別のWebサービスやソフトウェアから呼び出せるようにしたものです。
APIの正式名称は、Application Programming Interface(アプリケーション プログラミング インターフェース)といいます。
Slack APIを使うことで、メッセージの送信やユーザー情報の取得、チャンネル情報の取得など、Slackで様々な便利機能を提供するアプリを作成することができるようになります。

では、Googleの検索画面でSlack APIと検索し、公式サイトにアクセスしてください。
まずは、Slack APIには、どんなAPIがあり、どう使うのかを調べます。
Slack APIのトップページの右上の「Docs」のメニューを開いて「Web API methods」を選択します。
ここで、APIの一覧が表示されますので、必要なAPIを探すことができます。
今回は、「conversations」の「conversations.list」というAPIを使用します。
「conversations.list」は、ワークスペース内のすべてのチャンネル一覧を表示させることができます。
ここに記載されているURLは、のちほどプログラムを書くときに使用します。

Slack APIに登録

次に、Slack APIに登録をしましょう。
トップページにある「Create an app」というボタンをクリックします。
ここで、Slackにサインインがまだの方はサインインをして下さい。
サインインをしたら「From scratch」を選択し、「App Name」を「テスト」として、「Pick a workspace to develop your app in:」で情報を取得したいSlackのワークスペースを選択します。
今回は「KinoVillageTest」というワークスペースを使います。
選択して、「Create App」ボタンをクリックすると、アプリが作成されます。

アプリを作成できたら、作成したアプリをユーザーがインストールして、APIを使えるようにします。
「OAuth & Permission」 をクリックし、下の方にある「Scopes」を探します。
「Scopes」でアプリにスコープを追加することができます。
スコープとは、作成したアプリがどのような情報にアクセスし、どういった作業ができるかを設定するためのものです。
Web APIメソッドの呼び出しなどSlackでの機能を実行する権限をアプリに与えてアクセスします。
ここで、行いたい処理に必要なスコープを選択する必要があります。
スコープには、ボットとして API を実行するときのスコープを設定する 「Bot Token Scopes」と、ユーザーとして API を実行するときのスコープを設定する「User Token Scopes」があります。
今回は、「User Token Scopes」にスコープを設定します。
次に、「Add an OAuth Scope」をクリックします。
ここで必要なスコープを追加します。
パブリックチャンネルに関する情報の取得に必要なスコープとして、「channels:read」を追加します。
「channels:read」は、ワークスペース内のパブリックチャンネルに関する基本情報を表示するためのスコープです。

これに加えて、プライベートチャンネルやダイレクトメッセージの情報まで取得したい場合や、チャンネル一覧の取得後に、そのチャンネルのユーザーの情報を取得したい場合は、それに応じて必要なスコープをさらに追加する必要があります。
次のレッスンでは、チャンネルごとの発言数を取得する方法について説明します。こちらもご覧ください。

では、スコープを設定したら、同じページの1番上の「OAuth Tokens for Your Workspace」で「Install to Workspace」ボタンをクリックします。
権限をリクエストするための画面が表示されるので、「許可する」をクリックします。
アプリのインストールに成功すると、「User OAuth Token」というトークンが生成されます。
トークンは、コードに組み込むことで、ユーザーとして API を実行することができます。
これで、Slack APIの登録は完了です。

チャンネル一覧の取得

# !pip install requests

それでは、ここからPythonでコードを書いて、チャンネル一覧を取得しましょう。
では、今回のプログラムで使用するライブラリをインストールします。
ライブラリとは、よく使う機能や関数をまとめて簡単に使えるようにしたものです。
今回は、requestsというライブラリを使用します。
requestsとは、HTTP通信をするためのライブラリです。
例えば、特定のWebページにアクセスしたり、サーバーに指示を送ったりする役割をします。
Jupyter labでインストールするためには、「!pip install requests」とします。
実行します。
インストールできました。
すでにインストール済みの場合は、ここは実行する必要がありません。

#必要なライブラリのインストール
import requests
import json

次に、requestsライブラリとjsonモジュールをインポートします。
jsonモジュールは、取得したデータをjson形式で扱うために使用します。
json形式とは、データ交換フォーマットの一種です。
データをjson形式に変換することで、複雑なデータも読みやすいデータとして出力することができます。

#必要な変数の設定
#APIのURL
url = "    https://slack.com/api/conversations.list"
#取得したトークン
token = "取得したトークン"

次に、プログラムで使用する変数を設定します。
まず、アクセスする「conversations.list」のWeb APIのURLを変数urlに代入します。
このURLは、Slack APIの公式ドキュメントのconversations.listに記載されているURLをコピーして使用します。
このWebAPIにアクセスするためのURLをエンドポイントといいます。
次に、先ほど取得したトークンをコピーし、ダブルコーテーションで囲んで、変数tokenに代入します。
実行します。
2つの変数を設定できました。

headers = {"Authorization": "Bearer "+token}
headers
{'Authorization': 'Bearer 取得したトークン'}

Slack APIでは、トークンや送りたい内容などを指定の辞書型で渡す必要があります。
辞書型とは、keyとvalueが対になっているデータ型です。
Slack APIでは、認証情報のトークンは、「token」をkeyにした辞書型で渡す必要があります。
また、送りたい内容のkeyは、チャンネルのIDなら「channel」、テキストデータなら「text」と送りたい内容ごとに決まっています。
公式ドキュメントの各WebAPIのページの「Argument」の欄に、送りたい内容ごとのkeyが載っています。
「Argument」とは引数のことです。そちらを参照しながらkeyを設定しましょう。
今回は、トークン以外に送りたい内容は無いので、トークンの情報を新しい変数headersに代入します。
Slack apiではAuthorizationヘッダーにトークンを指定する必要があります。
Authorizationヘッダーを使ってHTTP上で認証を行う場合、Bearer認証を使用します。
Bearer認証とは、トークンを持っている所有者がapiにアクセスすることができる認証方法です。
確認のため、変数headersを表示させてみましょう。
実行します。
keyがheaders、valueに取得したトークンの、辞書が作成されていることを確認できました。

#チャンネル一覧の取得
response = requests.get(url, headers=headers)

それでは、すべてのチャンネルの一覧を取得してみましょう。
情報を取得するためには、postメソッドを使用します。
getメソッドは、サーバーからデータを取得するために使用するメソッドです。
第一引数に、アクセスするWebAPIのURL、引数headersに辞書型にしたトークンの変数headersを渡し、これを変数responseに代入します。

#オブジェクトを辞書型に変換
channel_data = response.json()
channel_data
{'ok': True,
 'channels': [{'id': 'C01E1EVJ679',
   'name': 'general',
   'is_channel': True,
   'is_group': False,
   'is_im': False,
   'is_mpim': False,
   'is_private': False,
   'created': 1605059346,
   'is_archived': False,
   'is_general': True,
   'unlinked': 0,
   'name_normalized': 'general',
   'is_shared': False,
   'is_org_shared': False,
   'is_pending_ext_shared': False,
   'pending_shared': [],
   'parent_conversation': None,
   'creator': 'U01EURRUUKT',
   'is_ext_shared': False,
   'shared_team_ids': ['T01F62LERQ8'],
   'pending_connected_team_ids': [],
   'is_member': True,
   'topic': {'value': '一般', 'creator': 'U01GHPK068H', 'last_set': 1607419952},
   'purpose': {'value': 'This is the one channel that will always include everyone. It’s a great spot for announcements and team-wide conversations.',
    'creator': 'U01EURRUUKT',
    'last_set': 1605059346},
   'previous_names': [],
   'num_members': 6},
  {'id': 'C01E9F7FZ7Y',
   'name': 's',
   'is_channel': True,
   'is_group': False,
   'is_im': False,
   'is_mpim': False,
   'is_private': False,
   'created': 1605059446,
   'is_archived': False,
   'is_general': False,
   'unlinked': 0,
   'name_normalized': 's',
   'is_shared': False,
   'is_org_shared': False,
   'is_pending_ext_shared': False,
   'pending_shared': [],
   'parent_conversation': None,
   'creator': 'U01EURRUUKT',
   'is_ext_shared': False,
   'shared_team_ids': ['T01F62LERQ8'],
   'pending_connected_team_ids': [],
   'is_member': True,
   'topic': {'value': '好きな音楽について自由に共有するチャンネル',
    'creator': 'U01GHPK068H',
    'last_set': 1607418518},
   'purpose': {'value': '好きな音楽をシェアして自由に楽しみましょう!',
    'creator': 'U01GHPK068H',
    'last_set': 1607418556},
   'previous_names': [],
   'num_members': 6},
  {'id': 'C01F62LF60G',
   'name': 'random',
   'is_channel': True,
   'is_group': False,
   'is_im': False,
   'is_mpim': False,
   'is_private': False,
   'created': 1605059346,
   'is_archived': False,
   'is_general': False,
   'unlinked': 0,
   'name_normalized': 'random',
   'is_shared': False,
   'is_org_shared': False,
   'is_pending_ext_shared': False,
   'pending_shared': [],
   'parent_conversation': None,
   'creator': 'U01EURRUUKT',
   'is_ext_shared': False,
   'shared_team_ids': ['T01F62LERQ8'],
   'pending_connected_team_ids': [],
   'is_member': True,
   'topic': {'value': 'ランダム',
    'creator': 'U01GHPK068H',
    'last_set': 1607420967},
   'purpose': {'value': 'This channel is for... well, everything else. It’s a place for team jokes, spur-of-the-moment ideas, and funny GIFs. Go wild!',
    'creator': 'U01EURRUUKT',
    'last_set': 1605059346},
   'previous_names': [],
   'num_members': 6},
  {'id': 'C01FN402SUB',
   'name': 'alerts',
   'is_channel': True,
   'is_group': False,
   'is_im': False,
   'is_mpim': False,
   'is_private': False,
   'created': 1606442632,
   'is_archived': False,
   'is_general': False,
   'unlinked': 0,
   'name_normalized': 'alerts',
   'is_shared': False,
   'is_org_shared': False,
   'is_pending_ext_shared': False,
   'pending_shared': [],
   'parent_conversation': None,
   'creator': 'U01EG7B43T4',
   'is_ext_shared': False,
   'shared_team_ids': ['T01F62LERQ8'],
   'pending_connected_team_ids': [],
   'is_member': True,
   'topic': {'value': '緊急なタスクについて',
    'creator': 'U01GHPK068H',
    'last_set': 1607418650},
   'purpose': {'value': 'すぐに対応が必要なタスクを共有しましょう。',
    'creator': 'U01GHPK068H',
    'last_set': 1607418642},
   'previous_names': [],
   'num_members': 6},
  {'id': 'C037CS1NY1J',
   'name': 'proj-1',
   'is_channel': True,
   'is_group': False,
   'is_im': False,
   'is_mpim': False,
   'is_private': False,
   'created': 1647435297,
   'is_archived': False,
   'is_general': False,
   'unlinked': 0,
   'name_normalized': 'proj-1',
   'is_shared': False,
   'is_org_shared': False,
   'is_pending_ext_shared': False,
   'pending_shared': [],
   'parent_conversation': None,
   'creator': 'U035HPXDKPW',
   'is_ext_shared': False,
   'shared_team_ids': ['T01F62LERQ8'],
   'pending_connected_team_ids': [],
   'is_member': True,
   'topic': {'value': '', 'creator': '', 'last_set': 0},
   'purpose': {'value': 'slackapiについて討論',
    'creator': 'U035HPXDKPW',
    'last_set': 1647435297},
   'previous_names': [],
   'num_members': 6}],
 'response_metadata': {'next_cursor': ''}}

次に、responseをjsonメソッドで辞書型に変換し、変数channel_dataに代入します。
channel_dataの値を表示させてみましょう。
実行します。
辞書型で、チャンネル一覧のデータが表示されました。

#インデントをつけてさらに見やすい形式に変換
channel_json = json.dumps(channel_data, indent=2)
print(channel_json)
{
  "ok": true,
  "channels": [
    {
      "id": "C01E1EVJ679",
      "name": "general",
      "is_channel": true,
      "is_group": false,
      "is_im": false,
      "is_mpim": false,
      "is_private": false,
      "created": 1605059346,
      "is_archived": false,
      "is_general": true,
      "unlinked": 0,
      "name_normalized": "general",
      "is_shared": false,
      "is_org_shared": false,
      "is_pending_ext_shared": false,
      "pending_shared": [],
      "parent_conversation": null,
      "creator": "U01EURRUUKT",
      "is_ext_shared": false,
      "shared_team_ids": [
        "T01F62LERQ8"
      ],
      "pending_connected_team_ids": [],
      "is_member": true,
      "topic": {
        "value": "\u4e00\u822c",
        "creator": "U01GHPK068H",
        "last_set": 1607419952
      },
      "purpose": {
        "value": "This is the one channel that will always include everyone. It\u2019s a great spot for announcements and team-wide conversations.",
        "creator": "U01EURRUUKT",
        "last_set": 1605059346
      },
      "previous_names": [],
      "num_members": 6
    },
    {
      "id": "C01E9F7FZ7Y",
      "name": "s",
      "is_channel": true,
      "is_group": false,
      "is_im": false,
      "is_mpim": false,
      "is_private": false,
      "created": 1605059446,
      "is_archived": false,
      "is_general": false,
      "unlinked": 0,
      "name_normalized": "s",
      "is_shared": false,
      "is_org_shared": false,
      "is_pending_ext_shared": false,
      "pending_shared": [],
      "parent_conversation": null,
      "creator": "U01EURRUUKT",
      "is_ext_shared": false,
      "shared_team_ids": [
        "T01F62LERQ8"
      ],
      "pending_connected_team_ids": [],
      "is_member": true,
      "topic": {
        "value": "\u597d\u304d\u306a\u97f3\u697d\u306b\u3064\u3044\u3066\u81ea\u7531\u306b\u5171\u6709\u3059\u308b\u30c1\u30e3\u30f3\u30cd\u30eb",
        "creator": "U01GHPK068H",
        "last_set": 1607418518
      },
      "purpose": {
        "value": "\u597d\u304d\u306a\u97f3\u697d\u3092\u30b7\u30a7\u30a2\u3057\u3066\u81ea\u7531\u306b\u697d\u3057\u307f\u307e\u3057\u3087\u3046\uff01",
        "creator": "U01GHPK068H",
        "last_set": 1607418556
      },
      "previous_names": [],
      "num_members": 6
    },
    {
      "id": "C01F62LF60G",
      "name": "random",
      "is_channel": true,
      "is_group": false,
      "is_im": false,
      "is_mpim": false,
      "is_private": false,
      "created": 1605059346,
      "is_archived": false,
      "is_general": false,
      "unlinked": 0,
      "name_normalized": "random",
      "is_shared": false,
      "is_org_shared": false,
      "is_pending_ext_shared": false,
      "pending_shared": [],
      "parent_conversation": null,
      "creator": "U01EURRUUKT",
      "is_ext_shared": false,
      "shared_team_ids": [
        "T01F62LERQ8"
      ],
      "pending_connected_team_ids": [],
      "is_member": true,
      "topic": {
        "value": "\u30e9\u30f3\u30c0\u30e0",
        "creator": "U01GHPK068H",
        "last_set": 1607420967
      },
      "purpose": {
        "value": "This channel is for... well, everything else. It\u2019s a place for team jokes, spur-of-the-moment ideas, and funny GIFs. Go wild!",
        "creator": "U01EURRUUKT",
        "last_set": 1605059346
      },
      "previous_names": [],
      "num_members": 6
    },
    {
      "id": "C01FN402SUB",
      "name": "alerts",
      "is_channel": true,
      "is_group": false,
      "is_im": false,
      "is_mpim": false,
      "is_private": false,
      "created": 1606442632,
      "is_archived": false,
      "is_general": false,
      "unlinked": 0,
      "name_normalized": "alerts",
      "is_shared": false,
      "is_org_shared": false,
      "is_pending_ext_shared": false,
      "pending_shared": [],
      "parent_conversation": null,
      "creator": "U01EG7B43T4",
      "is_ext_shared": false,
      "shared_team_ids": [
        "T01F62LERQ8"
      ],
      "pending_connected_team_ids": [],
      "is_member": true,
      "topic": {
        "value": "\u7dca\u6025\u306a\u30bf\u30b9\u30af\u306b\u3064\u3044\u3066",
        "creator": "U01GHPK068H",
        "last_set": 1607418650
      },
      "purpose": {
        "value": "\u3059\u3050\u306b\u5bfe\u5fdc\u304c\u5fc5\u8981\u306a\u30bf\u30b9\u30af\u3092\u5171\u6709\u3057\u307e\u3057\u3087\u3046\u3002",
        "creator": "U01GHPK068H",
        "last_set": 1607418642
      },
      "previous_names": [],
      "num_members": 6
    },
    {
      "id": "C037CS1NY1J",
      "name": "proj-\uff11",
      "is_channel": true,
      "is_group": false,
      "is_im": false,
      "is_mpim": false,
      "is_private": false,
      "created": 1647435297,
      "is_archived": false,
      "is_general": false,
      "unlinked": 0,
      "name_normalized": "proj-1",
      "is_shared": false,
      "is_org_shared": false,
      "is_pending_ext_shared": false,
      "pending_shared": [],
      "parent_conversation": null,
      "creator": "U035HPXDKPW",
      "is_ext_shared": false,
      "shared_team_ids": [
        "T01F62LERQ8"
      ],
      "pending_connected_team_ids": [],
      "is_member": true,
      "topic": {
        "value": "",
        "creator": "",
        "last_set": 0
      },
      "purpose": {
        "value": "slackapi\u306b\u3064\u3044\u3066\u8a0e\u8ad6",
        "creator": "U035HPXDKPW",
        "last_set": 1647435297
      },
      "previous_names": [],
      "num_members": 6
    }
  ],
  "response_metadata": {
    "next_cursor": ""
  }
}

これをさらに読みやすく変換します。
jsonモジュールのdumps関数を使用すると、整形されたJSON形式に変換することができます。
第一引数にJSON形式に変換したいデータであるchannel_dataを指定します。引数indentでインデントを指定できます。ここでは2を指定します。
これを変数channel_jsonに代入します。
表示させてみましょう。
実行します。
先ほどよりも見やすい形で、チャンネル一覧のデータが表示されました。
これで、Slackのワークスペース内のすべてのチャンネルの一覧のデータを取得することができました。

チャンネル名、チャンネルid、トピック、説明を取得

次は、取得した一覧から情報を抽出する方法について見てみましょう。
Slackのチャンネルには、チャンネル情報として、チャンネルのコンセプトを記す「トピック」とチャンネルの説明を記す「説明」を設定することができます。
今回は、各チャンネルのトピックと説明の情報を抽出し、取得してみましょう。

#トピックと説明を代入する辞書を用意
channeldict = {}

まず、辞書型の変数channeldictを用意します。
channeldictには、後ほど取得するチャンネルのid、トピック、説明のデータを格納します。

もう一度、先ほど取得したチャンネル一覧を見てみましょう。
「channel」というキーに対し、5つの辞書を要素とするリストがあります。そして、この5つの辞書が5つのチャンネルのデータであることがわかります。
辞書のキーの、「id」が各チャンネルの「id」、「name」が「チャンネル名」、「topic」が「トピック」、「purpose」が「説明」です。
これらのvalueが、それぞれの情報ということになります。

#idとtopicとpurposeをchannellistに代入
for i in channel_data["channels"]:
    channeldict[i["name"]] = {"id": i["id"],
                              "トピック": i["topic"],
                              "説明": i["purpose"]}
channeldict
{'general': {'id': 'C01E1EVJ679',
  'トピック': {'value': '一般', 'creator': 'U01GHPK068H', 'last_set': 1607419952},
  '説明': {'value': 'This is the one channel that will always include everyone. It’s a great spot for announcements and team-wide conversations.',
   'creator': 'U01EURRUUKT',
   'last_set': 1605059346}},
 's': {'id': 'C01E9F7FZ7Y',
  'トピック': {'value': '好きな音楽について自由に共有するチャンネル',
   'creator': 'U01GHPK068H',
   'last_set': 1607418518},
  '説明': {'value': '好きな音楽をシェアして自由に楽しみましょう!',
   'creator': 'U01GHPK068H',
   'last_set': 1607418556}},
 'random': {'id': 'C01F62LF60G',
  'トピック': {'value': 'ランダム', 'creator': 'U01GHPK068H', 'last_set': 1607420967},
  '説明': {'value': 'This channel is for... well, everything else. It’s a place for team jokes, spur-of-the-moment ideas, and funny GIFs. Go wild!',
   'creator': 'U01EURRUUKT',
   'last_set': 1605059346}},
 'alerts': {'id': 'C01FN402SUB',
  'トピック': {'value': '緊急なタスクについて',
   'creator': 'U01GHPK068H',
   'last_set': 1607418650},
  '説明': {'value': 'すぐに対応が必要なタスクを共有しましょう。',
   'creator': 'U01GHPK068H',
   'last_set': 1607418642}},
 'proj-1': {'id': 'C037CS1NY1J',
  'トピック': {'value': '', 'creator': '', 'last_set': 0},
  '説明': {'value': 'slackapiについて討論',
   'creator': 'U035HPXDKPW',
   'last_set': 1647435297}}}

では、for文でデータを順に取得しましょう。
channelsを順に取り出し、それぞれのデータを変数channeldictに格納します。
channeldictは、キーをチャンネル名に、valueには、チャンネルid、トピック、説明がセットの辞書にしましょう。
チャンネルidは「id」、トピックは「topic」、説明は「purpose」です。
表示してみましょう。実行します。

このように取得できました。

#インデントをつけてさらに見やすい形式に変換                              
channel_json = json.dumps(channeldict, sort_keys=True,
                          ensure_ascii=False, indent=2)
print(channel_json)
{
  "alerts": {
    "id": "C01FN402SUB",
    "トピック": {
      "creator": "U01GHPK068H",
      "last_set": 1607418650,
      "value": "緊急なタスクについて"
    },
    "説明": {
      "creator": "U01GHPK068H",
      "last_set": 1607418642,
      "value": "すぐに対応が必要なタスクを共有しましょう。"
    }
  },
  "general": {
    "id": "C01E1EVJ679",
    "トピック": {
      "creator": "U01GHPK068H",
      "last_set": 1607419952,
      "value": "一般"
    },
    "説明": {
      "creator": "U01EURRUUKT",
      "last_set": 1605059346,
      "value": "This is the one channel that will always include everyone. It’s a great spot for announcements and team-wide conversations."
    }
  },
  "proj-1": {
    "id": "C037CS1NY1J",
    "トピック": {
      "creator": "",
      "last_set": 0,
      "value": ""
    },
    "説明": {
      "creator": "U035HPXDKPW",
      "last_set": 1647435297,
      "value": "slackapiについて討論"
    }
  },
  "random": {
    "id": "C01F62LF60G",
    "トピック": {
      "creator": "U01GHPK068H",
      "last_set": 1607420967,
      "value": "ランダム"
    },
    "説明": {
      "creator": "U01EURRUUKT",
      "last_set": 1605059346,
      "value": "This channel is for... well, everything else. It’s a place for team jokes, spur-of-the-moment ideas, and funny GIFs. Go wild!"
    }
  },
  "s": {
    "id": "C01E9F7FZ7Y",
    "トピック": {
      "creator": "U01GHPK068H",
      "last_set": 1607418518,
      "value": "好きな音楽について自由に共有するチャンネル"
    },
    "説明": {
      "creator": "U01GHPK068H",
      "last_set": 1607418556,
      "value": "好きな音楽をシェアして自由に楽しみましょう!"
    }
  }
}

jsonモジュールのdumps関数を使用して、見やすくして表示しましょう。
引数sort_keysでキーをソートし、引数ensure_asciiで日本語表示をできるようにします。引数indentも指定しましょう。
実行します。
見やすく表示できました。

#channel.jsonファイルに書き込み                          
with open("channel.json", "w") as f:
    f.write(channel_json)

最後に抽出した情報を、jsonファイルに書き出してみましょう。
まず、with構文を使ってopen関数を開きます。引数にファイル名、モードはwを渡して書き込み用に指定します。
with構文とは、開始と終了の必須処理をセットで実行する構文のことです。この場合、openで開いたファイルを、処理が終わったらcloseと書かなくても自動でcloseの処理をします。
ファイル名は、channel.json とします。
asでオブジェクト名をfとし、コロンを書きます。
writeメソッドで書き込みをします。 JSON形式の変数channel_jsonを指定しましょう。
実行します。
channel.jsonというファイルが作成されました。
開いてみましょう。JSON形式のデータが書き込まれていることが確認できました。

おわりに

レッスンは以上です。
普段手作業でなにげなくやっていることも、実は自動化できることがたくさんあります。
プログラムを作ることは、はじめは簡単ではないかもしれませんが、ぜひチャレンジしてみてください。
小さなことからはじめて、少しずつ業務を効率化していってみましょう。

レッスンで使用したファイルはこちら

■保存方法
Mac:右クリック⇒「リンク先を別名で保存」
Windows:右クリック⇒「名前を付けてリンク先を保存」
Slack channel ipynbファイルはこちら