【Python】Word CloudによるInstagramハッシュタグの可視化

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2607838/1dc00402-de22-2ebc-4fca-457f8b489384.png)

# はじめに
デジタルマーケティングのインターンシップでInstagramの投稿を作成する機会があったのですが、キャプションのハッシュタグを考えるのが苦手で結構時間がかかっていました。

そこで、人気のハッシュタグ、あるいは最近よく使用されるタグが可視化されるツールがあれば良いなと思い、Word Cloudで可視化するプログラムを組みました。

ソースコードは[こちら](https://github.com/Nagayu71/instagram-tag-cloud)に上げております。
## 実行環境
- Windows 11
- Python 3.9.7 (Anaconda)
- Jupyter notebook (Anaconda)

## Instagram Graph API の利用
Instagram Graph APIを使用するためには以下の2つが必要となります。

- InstagramのビジネスアカウントID
- アクセストークン

それぞれの取得方法については、以下の記事がとても参考になりました。
※1つ目の記事にはトークン発行に必要なURLの「URL作成ツール」がありますが、ご利用はご自身の判断でお願いします。

- [Instagram Graph APIの基本的な使い方・Webサイトにインスタの写真を埋め込みする方法 | Arrown](https://arrown-blog.com/instagram-graph-api/) 
- [Instagram Graph APIとGAS（Google Apps Script）を使ってインスタグラムのフォロワー数を自動的に日々記録する - Qiita](https://qiita.com/joh_luck/items/af6f02c43e2f4497e15e) 

## トップ投稿と最新投稿の取得
Instagramは、特定のハッシュタグ付きの投稿を取得（ハッシュタグ検索）するAPIを公開しているので、簡単に投稿を取得することができます。
APIを介したハッシュタグ検索の流れは、次の通りです。
1. 検索したいハッシュタグの一意のIDを取得
2. 取得したハッシュタグIDと投稿タイプ、取得したい項目をURLに入れてデータをリクエスト（`requests`モジュール使用）
3. JSON形式のデータが返ってくる

しかし、APIの仕様上、一度のリクエストで取得できるのは最大50件までなので、それ以上取得したい場合は2回リクエストを送ります。以下は、ソースコードのコピペです。クラス内でメソッドとして定義しています。
参考資料：[Instagram APIでハッシュタグを収集しダッシュボードを作る方法 | 広報・PR支援の株式会社ガーオン](https://gaaaon.jp/blog/instagram#6046268f7fddd817442e2f7e-1616319060254) 

```python 
    # ハッシュタグIDを取得
    def get_hashtag_id(self, hashtag_query):
        # ハッシュタグID取得用URL
        ig_hashtagID_search_api = f"https://graph.facebook.com/ig_hashtag_search?user_id={self.business_account_id}&q={hashtag_query}&access_token={self.access_token}"
        # レスポンスをPythonが扱うことのできる対象（JSON）に変換し、IDを取得
        hash_id = requests.get(ig_hashtagID_search_api).json()['data'][0]['id']
        return hash_id
    
    # APIを叩いて見た目JSON形式のデータを取得
    def request_media(self, hashtag_query, search_type, num=100):
        # ハッシュタグID取得
        hash_id = self.get_hashtag_id(hashtag_query)
        
        # ハッシュタグ検索用URL
        if search_type == 'top':
            search_type = 'top_media'
        elif search_type == 'recent':
            search_type = 'recent_media'
        else:
            print("Error : 第2引数には、'top'か'recent'を入力してください")
        
        # 取得数に応じて条件分岐
        if num <= 50:
            hashtag_search_api = f"https://graph.facebook.com/{hash_id}/{search_type}?user_id={self.business_account_id}&fields={self.fields}&access_token={self.access_token}&limit={str(num)}"
            # レスポンスをPythonが扱うことのできる対象（JSON）に変換
            res_original = requests.get(hashtag_search_api).json()
            res_data = res_original['data']
        else:
            hashtag_search_api = f"https://graph.facebook.com/{hash_id}/{search_type}?user_id={self.business_account_id}&fields={self.fields}&access_token={self.access_token}&limit={str(num)}"
            # レスポンスをPythonが扱うことのできる対象（JSON）に変換
            res_original = requests.get(hashtag_search_api).json()
            res_data = res_original['data']
            # APIの仕様上、一度のリクエストで取得できるのは最大50件までなので、それ以上取得したい場合は2回リクエストを送る
            next_50_url = res_original['paging']['next']
            
            for data in requests.get(next_50_url).json()['data']:
                res_data.append(data) 
```

## 取得したキャプションの中からハッシュタグを抽出
APIを叩くと以下のようにJSON形式でデータが返ってきます。
```python
{
   "data": [
      {
         "id": "投稿ID",
         "media_type": "CAROUSEL_ALBUM",
         "media_url": "画像のURL",
         "permalink": "投稿へのリンク",
         "like_count": いいね数,
         "comments_count": コメント数,
         "caption": "本文",
         "timestamp": "投稿日時"
      }
   ],
   "paging": {
      "cursors": {
         "after": "1ページ目のURL"
      },
      "next": "2ページ目のURL"
   }
}
```
この`"caption"`の部分にキャプション本文が入っているので、ここから正規表現（`re`モジュール）を使用してハッシュタグを取得します。
もっと良いやり方があれば、ぜひ教えて下さい！
```python
    # キャプションから抽出したハッシュタグのリストを返す関数
    def extractHashtag(self, caption):
        pattern = r'#([^#\s$]+)'
        result = re.findall(pattern, caption)
        
        return result
```
## Word Cloud用にハッシュタグを集計
作成したクラス`InstagramTagCloud`の`.request_media()`メソッドは、次のような投稿IDをキー、キャプションに含まれるハッシュタグのリストを値とする辞書形式のデータを返します。
```python
print(hashtag_dict)

"""
{
 'ID_1': ['神戸グルメ', '神戸ランチ', '神戸カフェ', '神戸'],
 'ID_2': ['神戸', '神戸観光', '神戸旅行']
}
"""
```
これをWord Cloud表示用（ハッシュタグをキー、値を出現回数とする辞書）に集計します。
ここでは`collections`ライブラリの`collections.Counter`を用いてタグの出現回数をカウントし、上位30タグに絞ります。
```python
# ハッシュタグの集計
hashtag_list = []
for lst in hashtag_dict.values():
    # リスト同士の結合
    hashtag_list.extend(lst)
    
# ハッシュタグ集計プログラム
# collections.Counterを用いてタグの出現回数をカウントし、上位30タグを抽出
tag_count = dict(collections.Counter(hashtag_list).most_common(30))
```
## Word Cloudによる可視化
可視化の手順は以下の通りです。
1. wordcloudのインストール
2. 日本語のフォントをダウンロード
3. Word Cloudの生成＆描画

**1. wordcloudのインストール**
wordcloudのインストールは、Anaconda prompt を起動して、
`conda install -c conda-forge wordcloud`
でインストールできます。
参考：[wordcloud を Windows で Anaconda / Jupyter で使う（Tips） - Qiita](https://qiita.com/567000/items/5f4ea1e8268109ffc3b7)

**2. 日本語のフォントをダウンロード**
Word Cloudは日本語のフォントをこちらで準備しないと、表示がすべて豆腐（◻︎◻︎◻︎◻︎）になります。
そこで、[IPAex フォント Ver.004.01 | 一般社団法人 文字情報技術促進協議会](https://moji.or.jp/ipafont/ipaex00401/) のページから、
IPAexゴシック(Ver.004.01)をダウンロードし、適当な場所で解凍します。
展開したフォルダの中に、`ipaexg.ttf`ファイルがあるので、そのパスをコピーしておきます。

**3. Word Cloudの生成＆描画**
先ほどコピーした`ipaexg.ttf`ファイルのパスを`FONT_PATH`に格納し、引数として指定します。
`tag_count`を`.fit_words()`に渡すとWord Cloudが生成され、`matplotlib.pyplot`で描画します。
ちなみに、色の変更は`colormap`変数から調整可能です。
参考：[【日本語文章の表示サンプルあり】Pythonのワードクラウドで使えるカラーマップ一覧✰ matplotlib/WordCloud✰ - なろう分析記録](https://karupoimou.hatenablog.com/entry/2019/05/17/153207) 

```python
from wordcloud import WordCloud
import matplotlib.pyplot as plt

FONT_PATH = r'フォントの保存場所（フルパス）'
cloud = WordCloud(font_path=FONT_PATH, background_color='white', width=1000, height=600, colormap='bone').fit_words(tag_count)
plt.figure(figsize=(10, 8))
plt.imshow(cloud)
plt.axis('off')
plt.show()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2607838/8e539a88-40bb-1494-16c6-0bf56fe1855f.png)

## このプログラムの課題点
現時点で把握している本プログラムの課題点を記しておきます。

**ハッシュタグの抽出の精度**
今回、キャプションからハッシュタグを抽出する際、正規表現を使用しました。
これにより以下の場合にうまく取得することができません。
1. ユーザーが投稿のコメント欄にハッシュタグを付けている場合
2. ユーザーが適切なハッシュタグを付けていない場合

1については、APIから投稿と一緒にコメントを取得することができなかったため、未だ解決することができていません。
2については、ユーザーがたとえば、本来`#toypoodle`とすべきところを`#toy poodle`と間にスペースを入れていたり、`# hogehoge`としていたりする場合は、ユーザーの本来の意図とは別のハッシュタグとして拾ってしまいます。

# さいごに
最後までお読みいただき、ありがとうございます。
こういった記事を書くのは初めてで、読みにくい部分も多々あると思いますが、もしどなたかの役にたったのなら幸いです。