8
10

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 5 years have passed since last update.

私のチームでよく使われているSlack Emoji Reactions

Posted at

社内飲み会用のネタです :wink: :beers:
私の所属チームでよく使われているSlackのEmoji reactionsを集計しました。

結果

よく使われているSlack Emoji reaction上位7つです。
※数値は使用された回数

スクリーンショット 2016-09-16 17.38.40.png

というわけで、最も使われているのは :ok_woman: (:ok_woman:) でした。「了解」のつもりでよく使われますね。 :bow::bow:)も「よろしくお願いします」という感覚で使われやすい。

集計手順

Slackからチームのログをダウンロードする

OwnerかAdminの権限が必要です。
ダウンロードしたファイルを解凍すると次のようになっています。


  • :page_facing_up: users.json
  • :page_facing_up: channels.json
  • :page_facing_up: integration_logs.json
  • :file_folder: general
    • :page_facing_up: 2015-08-03.json
    • :page_facing_up: 2015-08-04.json
    • ...
  • :file_folder: random
    • :page_facing_up: 2015-08-03.json
    • :page_facing_up: 2015-08-04.json
    • ...
  • ...

チャネルごとディレクトリになっており、日別のファイルにJSON形式で格納されています。

ログをtsv形式に変換

reactionssだけ数えるならJSONから直接集計もできそうですが、汎用的に分析しやすいようtsvに変換しておきます。今回のスクリプトは Python 3.5.1 で実行しました。

convert_to_tsv.py
# -*- coding: utf-8 -*-
# ExportしたSlackの履歴ファイルからメッセージのログをtsvに出力するスクリプト

import json
import os
import shutil
import sys
import zipfile


class SlackLogs(object):

    def __init__(self, filepath):
        self.__cwd = os.getcwd()
        self.__tmp_dir = '__tmp'
        self.__unzip(filepath)
        self.__users = self.__fetch_users()
        self.__channels = self.__fetch_channels()

    def __unzip(self, filepath):
        self.delete_tmp_dir()
        os.mkdir(self.__tmp_dir)
        with zipfile.ZipFile(filepath, 'r') as zf:
            zf.extractall(path=self.__tmp_dir)

    def __fetch_users(self):
        users = {}

        u_fp = os.path.join(self.__tmp_dir, 'users.json')
        with open(u_fp, 'r') as f:
            data = json.load(f)
        for u in data:
            users[u['id']] = u['name']
        return users

    def __fetch_channels(self):
        fp = os.path.join(self.__tmp_dir, 'channels.json')
        with open(fp, 'r') as f:
            data = json.load(f)
        return [c['name'] for c in data]

    def __map_to_user_name(self, user_id):
        if user_id in self.__users:
            return self.__users[user_id]
        return user_id

    def __arrange_message(self, message, channel):
        def optional_user(m):
            if 'user' not in m:
                return ''
            return self.__map_to_user_name(m['user'])

        def optional_text(m):
            if 'text' not in m:
                return ''
            return m['text']

        def arrange_reactions(m):
            if 'reactions' not in m:
                return []
            a = []
            for r in m['reactions']:
                for u in r['users']:
                    a.append({'name': r['name'], 'user': self.__map_to_user_name(u)})
            return a

        return {
            'channel':   channel,
            'ts':        message['ts'],
            'type':      message['type'],
            'user':      optional_user(message),
            'text':      optional_text(message),
            'reactions': arrange_reactions(message)
        }

    def __fetch_messages(self):
        def fetch_messages_from_a_channel(channel):
            files = os.listdir(os.path.join(self.__tmp_dir, channel))
            messages = []
            for file in files:
                f_path = os.path.join(self.__cwd, self.__tmp_dir, channel, file)
                with open(f_path, 'r') as f:
                    data = json.load(f)
                    messages.extend([self.__arrange_message(m, channel) for m in data])
            return messages

        messages = []
        for c in self.__channels:
            messages.extend(fetch_messages_from_a_channel(c))

        messages.sort(key=lambda x: x['ts'])
        return messages

    def output_to_tsv(self):
        messages = self.__fetch_messages()
        f_path = os.path.join(self.__cwd, 'slack_logs.tsv')
        with open(f_path, 'w') as f:
            for m in messages:
                f.write('\t'.join([
                    m['channel'],
                    m['ts'],
                    m['type'],
                    m['user'],
                    m['text'].replace('\t', '\\t').replace('\n', '\\n').replace('\r', '\\r'),
                    json.dumps(m['reactions'])
                ]))
                f.write('\n')
        return

    def delete_tmp_dir(self):
        if os.path.exists(self.__tmp_dir):
            shutil.rmtree(self.__tmp_dir)

if __name__ == '__main__':
    filepath = os.path.join(os.getcwd(), sys.argv[1])
    if not os.path.exists(filepath):
        print('Not found {}'.format(filepath))
        exit()
    slack_logs = SlackLogs(filepath)
    slack_logs.output_to_tsv()
    slack_logs.delete_tmp_dir()
    print('Finised!')
実行と確認
$ ls
convert_to_tsv.py  Exportしたファイル.zip
$ python convert_to_tsv.py Exported_Files_from_Slack.zip
Finished!
$ ls
convert_to_tsv.py  Exportしたファイル.zip  slack_logs.tsv

Emojiごとにカウントする

次のスクリプトで全期間、全チャネル、全ユーザーにおけるEmojiごとのreaction回数を集計します。

count_emoji_reactions.py
# -*- coding: utf-8 -*-
# tsv形式のSlackログ履歴から集計する

import json
import os
import shutil
import sys
import zipfile
import re
import datetime


def count_emoji_reactions(logs):
    reactions = {}
    for m in logs:
        for r in m['reactions']:
            reactions.setdefault(r['name'], 0)
            reactions[r['name']] += 1

    for k, v in sorted(reactions.items(), key=lambda x: -x[1]):
        print(':{}: : {}'.format(k, v))

    return

def read_tsv(filepath):
    def format_log(line):
        log = line.rstrip().split('\t')
        try:
            return {
                'channel':   log[0],
                'ts':        float(log[1]),
                'type':      log[2],
                'user':      log[3],
                'text':      log[4],
                'reactions': json.loads(log[5])
            }
        except:
            print(log)
            exit()

    with open(filepath, 'r') as f:
        return [format_log(l) for l in f]

if __name__ == '__main__':
    filepath = os.path.join(os.getcwd(), sys.argv[1])
    if not os.path.exists(filepath):
        print('Not found {}'.format(filepath))
        exit()
    logs = read_tsv(filepath)
    count_emoji_reactions(logs)
実行と確認
$ ls
convert_to_tsv.py  count_emoji_reactions.py  Exportしたファイル.zip  slack_logs.tsv
$ python count_emoji_reactions.py slack_logs.tsv
:ok_woman: : 942
:bow: : 645
:+1: : 597
:raising_hand: : 465
:clap: : 298
:sushi_thanks: : 260
:pray: : 169
:sushi_kirakira: : 141
:tada: : 93
:sushi_yeah: : 92
:sushi_surprised: : 69
:innocent: : 67
:thinking_face: : 62
:meat_on_bone: : 58
:grinning: : 54
:eyes: : 50
:sushi_yes: : 43
:ok_hand: : 42
:smiley: : 42
:beastie: : 32
...

このままでは味気ないので結果をSlackにコピペしてしまいましょう。

8
10
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
8
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?