社内飲み会用のネタです
私の所属チームでよく使われているSlackのEmoji reactionsを集計しました。
結果
よく使われているSlack Emoji reaction上位7つです。
※数値は使用された回数
というわけで、最も使われているのは (:ok_woman:
) でした。「了解」のつもりでよく使われますね。 (:bow:
)も「よろしくお願いします」という感覚で使われやすい。
集計手順
Slackからチームのログをダウンロードする
OwnerかAdminの権限が必要です。
ダウンロードしたファイルを解凍すると次のようになっています。
- users.json
- channels.json
- integration_logs.json
-
general
- 2015-08-03.json
- 2015-08-04.json
- ...
-
random
- 2015-08-03.json
- 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にコピペしてしまいましょう。