LoginSignup
9
9

More than 5 years have passed since last update.

[Slack] プライベートチャンネルのポスト(POST)を一括でダウンロードするスクリプト書いてみた

Last updated at Posted at 2018-02-02

Slackのポスト(POST)について

ポスト はSlackの機能の一つで、通常よりも長文のメッセージや、書式付きのメッセージを投稿する場合に利用できます。投稿されたポストは複数人が共有して編集することも可能です。

image.png

あるプライベートチャンネルに多数のポストがあり、過去のものを一括ダウンロードしておきたいと思ったのですが、インポート & エクスポートの説明 を見ると、プライベートチャンネルからのエクスポートは「プラスデータエクスポート プラスプラン」が必要なようでした。

料金プランを見るとその価格は¥1,600(アクティブなユーザ1名あたり、年払いの場合の月額費用)。スタンダードの2倍弱となっており、このエクスポートのためだけにアップグレードするのはちょっと難しいので、APIを使用して一括ダウンロードするスクリプトを作ってみました。

処理の流れとスクリプト

API仕様を見たところ、プライベートチャンネルはAPIでは"group"となっており、以下の流れでポストの取得を実現できそうです。

1) 投稿したメッセージ一覧の取得にチャンネルのID(group id)が必要なため、まず groups.list メソッドでチャンネル一覧を取得
2) 一覧から、取得対象のグループをユーザが選択
3) 選択したチャンネルに対して、投稿されたメッセージの履歴を groups.history メソッドで取得
4) 各メッセージに対して、ポストがあればローカルファイルとしてダウンロード
5) groups.history メソッドでは一度に最大1000件しか取得できないため、続きがある場合(レスポンスに "has_more": true があれば)、 3) と 4)を繰り返す

この中で、4) の「ポストがあれば」の判定ですが、ポストはSlack内部的には「テキスト形式の添付ファイル」で実装されており、mimetype が'text/plain'である添付ファイルを全て取得するようにしました。APIレスポンスからは普通の共有ファイル(テキスト形式のファイルを添付した場合)と区別ができないので、共有ファイルもダウンロードされるようになっています。

作成したスクリプトが以下になります。

getFilesFromPrivateChannel.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from slackclient import SlackClient
import urllib2
import re
import datetime, time

# Slackのトークン
slack_token = '<ここにトークンを設定>'

# プライベートチャンネル(チャンネルID)のリストを取得
def getPrivateChannelIdList(slack_client):
  result = []
  group_list = slack_client.api_call(
    'groups.list',          # プライベートチャンネル取得APIは groups.list
    exclude_archived=False, # レスポンスにアーカイブチャンネルを含めるか(含める場合にFalse)
    exclude_members=True    # レスポンスにユーザ一覧を含めるか(含める場合にFalse)
  )

  if group_list['ok'] == True: # 正常なレスポンス
    groups = group_list['groups']
    for i in range(len(groups)):
      group_name = groups[i]['name']
      print str(i) + ' : ' + group_name # グループ名を標準出力
      result.append(groups[i]['id'])    # グループIDをリストに追加
  else:
    print 'Error at groups.list API:',
    print group_list

  return result

# チャンネルに投稿されたメッセージを取得し、ポスト(テキスト形式の添付ファイル)があればファイル出力
def outputFilesFromChannel(slack_client, channel_id):

  latest_time = 9999999999.999999 # 厳密には現在時刻だがこれでもOK
  has_more = 1 # チャンネルに1000件を超える投稿があれば1000件ごとに繰り返す
  while has_more == 1:
    comment_list = slack_client.api_call(
      'groups.history',   # 投稿取得APIは groups.history
      channel=channel_id,
      latest=latest_time,
      count=1000          # 1度に取得できる件数は最大1000件
    )

    if comment_list['ok'] == True:
      for comment in comment_list['messages']: # 各投稿をチェック

        latest_time = comment['ts']
        if comment.has_key('subtype') and comment['subtype'] == 'file_share' and \
           comment.has_key('file') and comment['file'].has_key('mimetype') and \
           comment['file']['mimetype'] == 'text/plain':

          # ファイル共有があり、かつそのmimetypeがテキスト形式の場合のみ、添付ファイルを出力
          file_title = comment['file']['title']
          file_timestamp = datetime.datetime.fromtimestamp(comment['file']['timestamp'])
          out_file_name = file_timestamp.strftime('%Y-%m-%d_%H%M%S') + '_' + comment['file']['id'] + '.txt'

          # ダウンロードはAPIが無いので、ヘッダにtoken設定してurllib2で取得
          req = urllib2.Request(comment['file']['url_private_download'])
          req.add_header('Authorization', 'Bearer ' + slack_token)
          with open(out_file_name, 'wb') as myfile:
            myfile.write(urllib2.urlopen(req).read())
            print 'Output : ' + out_file_name + '(' + file_title + ')'

      if comment_list['has_more'] == False: # 1000件以下なら終了
        has_more = 0

    else:
      print 'Error at groups.history API:',
      print comment_list
      break

  return

if __name__ == '__main__':

  slack_client = SlackClient(slack_token)

  private_channel_list = getPrivateChannelIdList(slack_client) # チャンネル一覧取得

  if len(private_channel_list) > 0:
    print 'Select channel num(0-' + str(len(private_channel_list)-1) + '):',
    input = raw_input() # 標準入力から対象チャンネルを選択

    channel_id = private_channel_list[int(input)]
    outputFilesFromChannel(slack_client, channel_id) # 選択したチャンネルに対して、ファイル出力
  else:
    print 'private channel num is 0'

実行してみる

実行にはトークンが必要となるので、以下より取得します。未発行の場合は「Create token」で発行して下さい。
https://api.slack.com/custom-integrations/legacy-tokens

スクリプト10行目の <ここにトークンを設定> に設定し、スクリプトを実行します。slackclient がインストールされていない場合は先にインストールして下さい。

pip install slackclient

実行例:

$ python getFilesFromPrivateChannel.py
0 : team-general
1 : team-randam
2 : team-meeting
3 : test-a17
4 : test-a18
5 : test-a19
Select channel num(0-5): 1
Output : 2018-01-25_151642_F8ZCQA19V.txt(ポスト(POST))
Output : 2017-12-20_112936_F8GFXA4D9.txt(2017-12-21 - メモ)
Output : 2017-11-22_160327_F83BM9KEU.txt(2017-11-22 - メモ)
Output : 2017-10-25_143619_F7P27V5QE.txt(2017-10-26 - メモ)
$ cat 2018-01-25_151642_F8ZCQA19V.txt
{"version":100,"revision":139,"root":{"children":[{"type":"p","text":"・これが"},{"type":"p","text":"・ポスト"},
{"type":"p","text":"・POST"},{"type":"p","text":"・通常よりも"},{"type":"p","text":"・長めの"},{"type":"p","text"
:"・メッセージ"},{"type":"p","text":"・複数人で","formats":{"i":[0,5]}},{"type":"p","text":"・共有しての","formats
":{"i":[0,6]}},{"type":"p","text":"・編集も可能","formats":{"i":[0,6]}},{"type":"p","text":""}]}}

うまくダウンロードできたようです。ファイルはjson形式になっているので、必要に応じて整形して利用できます。

9
9
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
9
9