[Python自動化] Slackのユーザーアイコンを絵文字化する [SlackAPI]

## つくったもの

Slackのユーザーアイコンを絵文字化してくれるスクリプトを書きました。
↓こんな感じでユーザーのアイコンがそのままリアクションに使えるようになります。（**誰がリアクションしたのかひと目でわかって便利？？**）

![スクリーンショット 2019-11-10 12.41.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206591/bc7f1e97-4ac5-422b-dc1f-e86fd91baeb6.png)


てっとり早く使いたい人はリポジトリを見て下さい。
https://github.com/KoseiYoshida/slack_usericon_to_emoji




こっから先はスクリプトの中身を解説していきます。

解説見なくてもリポジトリ見ればやってることはわかると思います。
が、せっかく作ったので、自分のアウトプットも兼ねてスクリプトの解説記事を書いてみました。

## 想定読者

* SlackAPIを使って情報を取得していく流れを見たい人
* Python使って何かしら実用的なものを作ってみたい初心者

## 開発環境

* macOS Mojave 10.14.16
* Python 3.7.4

なお、**この記事に書いてあるコードは解説のために簡略したもの**です。
ちゃんと動くコードが見たい人はリポジトリを見て下さい。

## 作業のながれ

1. SlackAPIにアクセスするためのTokenを取得する
2. ユーザー情報をAPI経由で取得する
3. ユーザー全員のアイコン画像をダウンロードしてくる
4. ダウンロードした画像をまとめてアップロードする


## 1. Tokenの取得

ここではSlackのユーザー情報の取得に必要なTokenの取得をやっていきます。
Token取得の経験ある方は下のほうに書いてあるOAuthScopeの登録だけ見てもらえば大丈夫です。

SlackAPIのToken取得方法はこの記事を参考にしました。
[Slack API 推奨Tokenについて](https://qiita.com/ykhirao/items/3b19ee6a1458cfb4ba21)



では実際にTokenを取得していきます。
>SlackAPIには、推奨TokenとレガシーTokenの2種類がありますが、
この記事では、推奨Token使って進めていきます。
めんどくさい人は取得が簡単なレガシーTokenでも大丈夫です。

基本的なやり方は、上のリンクにある「GUIでTokenを取得する方法」をみてください。
アプリ名と追加するワークスペースを選択してCreateAppできたら、次にScopeを追加していきます。  

![スクリーンショット 2019-11-10 13.01.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206591/6fc41863-d88e-9209-6f1b-5e9ecc506a7d.png)
(画像だとPermissionsにチェックがついていますが、初期状態だと何もないです）

* IncomingWebhooksを選択してONにする
* Permissionを選択し、下の方にあるScopesの項目を追加していきます
    * Add an OAuth Scopeをして追加していってください
        * identify
        * users:read
        * emoji:read

うまくいくと、下のような感じになると思います。
![スクリーンショット 2019-11-10 13.01.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206591/1c1b0798-74ac-108c-14c5-4080994ea8e9.png)

これで設定ができたので、Permissionの画面にあるInstallAppToWorkspaceボタンを押します。
指示にしたがってインストールが成功すると、OAuthAcessTokenが表示されるはずです！

これでTokenがつくれたので、ユーザー情報にアクセスしていきます。

## 2. ユーザー情報の取得

ここでは先ほど取得したTokenを使ってユーザー情報にアクセスし、アイコン画像のURLなどを取得していきたいと思います。

ユーザー情報を取得するときは
`https://slack.com/api/users.list?token=<取得したトークン>`
にGETリクエストすれば良いみたいです。
ついでにjsonの形で取得して扱いやすくします。

```python
USERLIST_GETURL_BASE = 'https://slack.com/api/users.list?token='
TOKEN = <取得したトークン>

def get_userslist_json():
    # json形式で取得できるようにheaderを指定する
    headers = {'content-type': 'application/json'}
    res = requests.get(USERLIST_GETURL_BASE + TOKEN, headers)
    users_list = res.json()
    # 実際のデータは'members'の中にある。なのでそれ以外は捨てる
    users_list = users_list['members']
    return users_list
```

responseの中で必要な項目は'members'のみなので、他は捨ててしまいましょう。

取得できたリストには要素ひとつがユーザー1人分の情報（辞書型）になっています。
↓ユーザーの一人分の情報。辞書型で色んな項目がならんでいます。

```
{'id': 'UQ412C941',
  'team_id': 'TBASP22UV',
  'name': 'koseiasengineer',
  'deleted': False,
  'color': 'e7392d',
  'real_name': 'Pig',
  'tz': 'Asia/Tokyo',
  'tz_label': 'Japan Standard Time',
  'tz_offset': 32400,
  'profile': {'title': '',
   'phone': '',
   'skype': '',
   'real_name': 'Pig',
   'real_name_normalized': 'Pig',
   'display_name': '豚太郎',
   'display_name_normalized': '豚太郎',
   'status_text': '',
   'status_emoji': '',
   'status_expiration': 0,
   'avatar_hash': '1b04567a2fd5',
   'image_original': 'https://avatars.slack-edge.com/2019-11-09/815178912706_1b04567a2fd5434e2659_original.png',
   'is_custom_image': True,
   'first_name': 'Pig',
   'last_name': '',
   'image_24': 'https://avatars.slack-edge.com/2019-11-09/815178912706_1b04567a2fd5434e2659_24.png',
   'image_32': 'https://avatars.slack-edge.com/2019-11-09/815178912706_1b04567a2fd5434e2659_32.png',
   'image_48': 'https://avatars.slack-edge.com/2019-11-09/815178912706_1b04567a2fd5434e2659_48.png',
   'image_72': 'https://avatars.slack-edge.com/2019-11-09/815178912706_1b04567a2fd5434e2659_72.png',
   'image_192': 'https://avatars.slack-edge.com/2019-11-09/815178912706_1b04567a2fd5434e2659_192.png',
   'image_512': 'https://avatars.slack-edge.com/2019-11-09/815178912706_1b04567a2fd5434e2659_512.png',
   'image_1024': 'https://avatars.slack-edge.com/2019-11-09/815178912706_1b04567a2fd5434e2659_1024.png',
   'status_text_canonical': '',
   'team': 'TBASP22UV'},
  'is_admin': False,
  'is_owner': False,
  'is_primary_owner': False,
  'is_restricted': False,
  'is_ultra_restricted': False,
  'is_bot': False,
  'is_app_user': False,
  'updated': 1573257843,
  'has_2fa': False}
```

**'image_original', 'image_<解像度>' にアイコン画像が置いてあるようです。**
名前は色々種類があるみたいですが、**Slackのユーザーとして普段見えてる名前は'display_name'に入ってる**みたいです。
> real_name

アイコン画像のありかがわかったので、ダウンロードしていきます。

## 3. ユーザーアイコンのダウンロード

SlackPI経由で取得したユーザー情報からアイコン画像のありかがわかったので、ダウンロードしていきます。
画像の保存名 = Emojiの名前となることを想定しています。

基本は単純に画像を取得し保存するだけなのですが、問題点があります。

* 取得したユーザー情報には、Botや過去に所属していたユーザーの情報が含まれている
* Emojiのアップロードに使うスクリプトが日本語に対応していない
    * (Slackのユーザー名はローマ字で登録されていたり、日本語で登録されてたり結構マチマチ）

ということで、これらの問題を解決していきます。


### Botや過去に所属していたユーザーをはじく
先程取得したユーザー情報をみると、'is_bot'や'is_deleted'などの項目が用意されています。
これらの項目をつかってはじきます。

```python

# 引数memberにはユーザー情報の一人分（辞書型）がくる想定。
def is_target_member(member):

    if member['is_bot']:
        return False

    # デフォルトで参加しているSlackBotは'is_bot'が何故かFalseになっているため、名前ではじく
    if member['name'] == 'slackbot':
        return False

   if member['deleted'] == 'True':
        return False

    return True
```
Workspaceを作った時点で最初からいるSlackBotは、なぜか'is_bot'フラグがFalseなので、名前で無理やりはじきます。

### 日本語をローマ字化する

「pykakasi」というパッケージで、日本語（漢字、カタカナ、ひらがな）をローマ字に変換できるようです。
(参考、[日本語文字をローマ字に変換するpykakasiモジュールのインストールと利用について](https://qiita.com/komorin0521/items/8cd1eb0cdb4a9ede217e))
ついでに、全角->半角に変換してくれる「mojimoji」もいれておきます。

```bash
$ pip install git+https://github.com/miurahr/pykakasi
$ pip install mojimoji
```

こんな感じでローマ字化します。

```python
from pykakashi import kakashi
import mojimoji

def fix_name_style(name):
        
    jpn2romaji = kakasi()
    jpn2romaji.setMode('J', 'a')
    jpn2romaji.setMode('K', 'a')
    jpn2romaji.setMode('H', 'a')
    k2r_conv = jpn2romaji.getConverter()
    fixed_name = k2r_conv.do(name)

    fixed_name = mojimoji.zen_to_han(fixed_name)

    # ドットやスペースはエラーにつながるので削除しておく
    fixed_name = fixed_name.replace(".", "")
    fixed_name = fixed_name.replace(' ', '')

    return fixed_name
```

### ダウンロードまとめ

問題が解決できたので、いよいよダウンロードしていきます。
画像ダウンロード用の関数を書いて、全体像はこんな感じになります。
（↓はあくまで処理の流れを掴んでもらうためのコードです。ちゃんと動くものはリポジトリを見て下さい。）

```python

def download_file(self, url, dst_path):
    with urllib.request.urlopen(url) as web_file, open(dst_path, 'wb') as local_file:
        local_file.write(web_file.read())

save_directory_name = 'temp' # 名前はなんでもいい
members_list =　get_userslist_json()

for member in members_list:
    # Botや退会したユーザーをはじく
    if not is_target_member(member):
        continue

    member_prof = member['profile']

    name = member_prof['display_name'].lower()
    name = fix_name_style(name)

    # 'image_original'にアイコン画像のurlが入っている
    image_url = member_prof['image_original']
    _, ext = os.path.splitext(image_url)

    saved_file_path = './' + save_directory_name + os.sep + name + ext
    download_file(image_url, saved_file_path)
```

## 4. 絵文字の追加

保存した画像を絵文字として追加するのは、こちらの"slack-emojinator"を使わせていただきます。
https://github.com/smashwilson/slack-emojinator
README.mdにかかれている通りやっていけば大丈夫だと思います。
（日本語の説明がよければここに、[Slack emojinator使ってみた](https://qiita.com/it__ssei/items/ffb6c8f1baa4f6f87d26 ))

ちなみに、"slack-emojinator"による絵文字の追加ですが、
SlackAPIには絵文字追加用のAPIが用意されていないため、Cookieを使って無理やりSessionをつくっているようです。


"slack-emojinator"はコマンドラインから呼び出して使います。
画像ダウンロードからアップロードまでを全自動でやりたい場合には以下のリポジトリを参照してください。
https://github.com/KoseiYoshida/slack_usericon_to_emoji

## まとめ

Slackのユーザーアイコンを取得->絵文字化をPythonで自動化しました。
リポジトリをクローンすれば簡単に実行できるので、是非使ってみてください。

PythonやAPIに不慣れのためコード汚くてすいません。マサカリ歓迎です。