Pythonを用いてツイートデータからWord Cloudの作成

# はじめに
Twitterのデータを取得し，Word Cloudを作成することで，そのアカウントがどのようなツイートをしているのかを可視化します．

# 開発環境
- macOS
- Python 3.9.2

# 事前準備
ツイートのデータを取得する際にTwitter APIを使用するため，[APIを取得](https://www.torikun.com/entry/twitter-developer-api/)しておきます．


# ツイートデータの取得
はじめに必要なライブラリをインストールします．

```
pip install requests-oauthlib
pip install janome
pip install wordcloud
pip install emoji --upgrade
pip install python-dotenv
```

次に，Twitter APIキーを環境変数に設定します．APIキーをソースコード中に直に記述するのは良くないため，環境変数に設定します．「[.env](https://qiita.com/harukikaneko/items/b004048f8d1eca44cba9)」ファイルを作成しファイルに記述しても可です．

```
API_KEY=***********
API_S_KEY=************************
ACCESS_TOKEN=*******************************
ACCESS_TOKEN_S=***********************************
```

環境変数に設定されたAPIキーをpythonから読み込みます．今回は「config.py」というファイル名でプログラムを保存します．

```config.py
from dotenv import load_dotenv
load_dotenv()

# 環境変数を参照
import os

CK = os.getenv('API_KEY')
CS = os.getenv('API_S_KEY')
AT = os.getenv('ACCESS_TOKEN')
ATS = os.getenv('ACCESS_TOKEN_S')
```

config.pyをimportしてツイートを取得しファイルに保存するプログラムを作成します．
絵文字の除去は，[このサイト](https://qiita.com/yoshimo123/items/85331d881aed9ad41020)のプログラムでは，バージョンの違いで除去ができないため，少し修正する必要があります．

```get_user_timeline.py
import json
import config
from requests_oauthlib import OAuth1Session
from time import sleep
import emoji
import argparse

parser = argparse.ArgumentParser(description='ツイートのデータを取得しファイルに保存')
# オプション引数
parser.add_argument('-u','--username',help='取得するアカウントの@以降のアカウト名')
parser.add_argument('-o','--output',default='tweet_data.dat',help='ツイートを保存するファイル名')

args = parser.parse_args()

# 絵文字を除去する
def remove_emoji(src_str):
    return ''.join(c for c in src_str if c not in emoji.UNICODE_EMOJI['en'])


# 認証処理
twitter = OAuth1Session(config.CK, config.CS, config.AT, config.ATS)  

# タイムライン取得エンドポイント
url = "https://api.twitter.com/1.1/statuses/user_timeline.json"  

# 引数にユーザー名が指定されていない場合は，標準入力で取得
if args.username is None:
    username = input('@以降のアカウント名: ')
else:
    username = args.username

# パラメータの定義
params = {'screen_name': username,
          'exclude_replies': True,
          'include_rts': False,
          'count': 200}

# 出力先ファイル
f_out = open(args.output, 'w')

for j in range(100):
    res = twitter.get(url, params=params)
    if res.status_code == 200:
        # API残り回数
        limit = res.headers['x-rate-limit-remaining']
        print("API remain: " + limit)
        if limit == 1:
            sleep(60*15)

        n = 0
        timeline = json.loads(res.text)
        # 各ツイートの本文を保存
        for i in range(len(timeline)):
            if i != len(timeline)-1:
                # 絵文字を削除する
                f_out.write(remove_emoji(timeline[i]['text']) + '\n')
            else:
                # 絵文字を削除する
                f_out.write(remove_emoji(timeline[i]['text']) + '\n')
                # 一番最後のツイートIDをパラメータmax_idに追加
                params['max_id'] = timeline[i]['id']-1

f_out.close()
```

## 実行コマンド
```
python3 get_user_timeline.py [-u アカウント名] [-o 出力ファイル名]
```

コマンドライン引数でアカウント名とツイートデータの出力ファイル名を指定して実行します．
アカウント名を省略した場合は，標準入力でアカウント名の入力が求められます．
出力ファイル名を省略した場合は「tweet_data.dat」というファイルに出力します．

# Word Cloudの作成
ファイルに保存されたツイートのデータからWord Cloudを作成します．

```twitter_wordcloud.py
import csv
from janome.tokenizer import Tokenizer
import matplotlib.pyplot as plt
from wordcloud import WordCloud
from bs4 import BeautifulSoup
from collections import Counter, defaultdict
import argparse

parser = argparse.ArgumentParser(description='保存されたツイートのデータからwordcloudを作成')
# オプション引数
parser.add_argument('-i','--input',default='tweet_data.dat',help='ツイートが保存されているファイル名')
parser.add_argument('-o','--output',default='wordcloud.png',help='出力するファイル名')

args = parser.parse_args()

# 名詞だけ抽出、単語をカウント
def counter(texts):
    t = Tokenizer()
    words_count = defaultdict(int)
    words = []
    for text in texts:
        tokens = t.tokenize(text)
        for token in tokens:
            # 品詞から名詞だけ抽出
            pos = token.part_of_speech.split(',')[0]
            if pos in ['名詞']:
                # 必要ない単語を省く(実際の結果を見てから不必要そうな単語を記載しました)
                if token.base_form not in ["こと", "よう", "そう", "これ", "それ"]:
                    words_count[token.base_form] += 1
                    words.append(token.base_form)
    return words_count, words

with open(args.input, 'r') as f:
    reader = csv.reader(f, delimiter='\t')
    texts = []
    for row in reader:
        if(len(row) > 0):
            text = row[0].split('http')
            texts.append(text[0])

words_count, words = counter(texts)
text = ' '.join(words)

# fontは自分の端末にあるものを使用する
fpath = "~/Library/Fonts/RictyDiminished-Bold.ttf"
wordcloud = WordCloud(background_color="white",
                      font_path=fpath, width=900, height=500).generate(text)

wordcloud.to_file(args.output)
```

## 実行コマンド
```
python3 twitter_wordcloud.py [-i 読み込むファイル名] [-o 出力するファイル名]
```
コマンドライン引数で読み込むファイル名と出力する画像のファイル名を指定して実行します．
読み込むファイル名を省略した場合は「tweet_data.dat」から読み込みます．
出力するファイル名を省略した場合は「wordcloud.png」というファイル名で保存されます．

# 実行例
今回はAtCoder社長のchokudaiさん([@chokudai](https://twitter.com/chokudai))のツイートデータを取得して可視化をしてみたいと思います．

```
python3 get_user_timeline.py -u @chokudai
python3 twitter_wordcloud.py
```

実行結果は次のようになりました．

![wordcloud.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/668961/2df76da8-67fb-6b9a-1329-daf98e3c5ab3.png)


# 参考
- [Word Cloudでツイートを可視化してみた(python)](https://qiita.com/turmericN/items/04cd0b40f91076f0ef42)
- [pythonで絵文字を駆逐する](https://qiita.com/yoshimo123/items/85331d881aed9ad41020)
- [https://github.com/carpedm20/emoji/issues/155](https://github.com/carpedm20/emoji/issues/155)