TwitterAPIを使って特定のキーワードを含むツイート可視化

## 概要
・TwitterのAPIを利用して直近１週間の特定のキーワードを含むツイート可視化
　①レンタルサーバーのツイート数推移（時間）をプロット
　②直近１週間のレンタルサーバーのツイート数推移（日）をプロット
　③頻出ワードのランキング

##今後やってみたいこと
・TwitterAPIを使った特定キーワードのネガポジ分析
・クラスタ分析

## 環境
Python 3.5.2
Jupyter Notebook

## 前準備
Twitter APIを使用するには[デベロッパー](https://developer.twitter.com/en/apps/)申請が必要。

## 実装
```python

import json
from requests_oauthlib import OAuth1Session, OAuth1
import requests

#requests-oauthlibという Python 用の OAuth 認証ライブラリを用いてアクセスする。
#Requestsは、 Python の HTTP 通信ライブラリ。 
#Requests を使うとWebサイトの情報取得や画像の収集などを行うことができる。

#TwitterのAPI-keyを入力
KEYS = {
    'consumer_key':'-----------------',
    'consumer_secret':'-----------------',
    'access_token':'-----------------',
    'access_secret':'-----------------',
}
twitter = OAuth1Session(KEYS['consumer_key'],KEYS['consumer_secret'],KEYS['access_token'],KEYS['access_secret'])

## ツイート情報取得用エンドポイントURL
url = "https://api.twitter.com/1.1/search/tweets.json"

#Standard search APIでツイートの取得
#result_type：取得するツイートの種類が選択できる　recentは、最新のツイート
params ={'q': "key_word", 'count':'100','lang':'ja', 'result_type':'recent'}

res = twitter.get(url, params = params)

def getTwitterData(key_word, repeat):
    url = "https://api.twitter.com/1.1/search/tweets.json"
    params ={'q': key_word, 'count':'100','lang':'ja', 'result_type':'recent'}
    tweets = []
    mid = -1
    break_flag = 0

#max_idは、取得Tweetの範囲の指定
#res = twitter.get(url, params = params)でTwitterからデータを取得
# if res.status_code == 200:　　httpレスポンスステータスコードで成功した場合200が返ってきた場合以下の処理をする
#sub_tweets = json.loads(res.text)['statuses']　：['statuses']　のデータをとってくる
# limit = res.headers['x-rate-limit-remaining'] if 'x-rate-limit-remaining' in res.headers else 0  :['x-rate-limit-remaining'] の値があったらその値を入れてなかったら０にする

    for i in range(repeat):
        params['max_id'] = mid
        res = twitter.get(url, params = params)
        if res.status_code == 200:
            sub_tweets = json.loads(res.text)['statuses']
            limit = res.headers['x-rate-limit-remaining'] if 'x-rate-limit-remaining' in res.headers else 0          
            tweet_ids = []
            for tweet in sub_tweets:
                tweet_ids.append(int(tweet['id']))
                tweets.append(tweet)
            if len(tweet_ids) > 0:
                min_tweet_id = min(tweet_ids)
                mid = min_tweet_id - 1
            else:
                break_flag = 1
                break;  
            ## 終了判定
            if break_flag == 1:
                break;            
        else:
            print("Failed: %d" % res.status_code)
            break_flag = 1
    print("ツイート取得数：%s" % len(tweets))
    return tweets

tweets = getTwitterData("レンタルサーバー", 180)
ツイート取得数：1965

import pandas as pd
df_tweet = pd.DataFrame(tweets)
display(df_tweet.info())
df_tweet.dtypes

#エラーが出たのでデータの型をdf_tweet.dtypesで確認。「created_at」がobjectであるためエラーが起きていた

#日付の文字列の列に対してto_datetime()を適用し、datetime64[ns]型に変換
df_tweet['created_at'] = pd.to_datetime(df_tweet['created_at'])

#変更を確認
df_tweet.dtypes

```
データ型の確認

```python
created_at                   datetime64[ns, UTC]
id                                         int64
id_str                                    object
text                                      object
truncated                                   bool
entities                                  object
extended_entities                         object
metadata                                  object
source                                    object
in_reply_to_status_id                    float64
in_reply_to_status_id_str                 object
in_reply_to_user_id                      float64
in_reply_to_user_id_str                   object
in_reply_to_screen_name                   object
user                                      object
geo                                       object
coordinates                               object
place                                     object
contributors                              object
is_quote_status                             bool
retweet_count                              int64
favorite_count                             int64
favorited                                   bool
retweeted                                   bool
possibly_sensitive                        object
lang                                      object
retweeted_status                          object
quoted_status_id                         float64
quoted_status_id_str                      object
dtype: object
```
この中で、分析によく使いそうな項目

|  |   | 
|:-:|---|
|created_a | UTC+0（グリニッジ標準時）であるため、日本時間が必要な場合は変換が必要 | 
|text   | ツイート本文が含まれている。 | 
| user  |ツイートしたユーザ情報が含まれている。フォロワー数やユーザ登録日など、複数の情報を含んでいる。リツイート数など、様々な情報を引き出すことが可能| 

### 直近１週間の時間毎のレンタルサーバーのツイート数推移をプロット

```python
import matplotlib.pyplot as plt
import seaborn as sns

plt.figure(figsize=(20,5))
g = sns.barplot(x="created_at", y="id", data=df_tweet.set_index("created_at").resample("H")["id"].count().reset_index())
labels = g.get_xticklabels()
g.set_xticklabels(labels, rotation=90)
plt.show()
```

<b>6月13日取得（集計期間：6月5日〜6月13日）</b>
![Twitter01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256115/357920d9-6645-3a2a-0f9a-c8dfd136fe7a.png)

<b>7月3日取得（集計期間：6月25日〜7月3日）</b>
![twitter_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256115/43fa28c5-611a-3d00-cd83-ac42cb3fc065.png)
6月に比べてレンタルサーバーを含むツイートが減少

### 日別でプロットする
```python
plt.figure(figsize=(20,5))
g = sns.barplot(x="created_at", y="id", data=df_tweet.set_index("created_at").resample("D")["id"].count().reset_index())
labels = g.get_xticklabels()
g.set_xticklabels(labels, rotation=90)
plt.show()

```
<b>6月13日取得（集計期間：6月5日〜6月13日）</b>
　　2021年6月10日にツィートが多いのは、fastlyの障害の影響かな
![Twitter02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256115/519cd1c6-f8b1-b8f9-f341-c63550686e87.png)

<b>7月3日取得（集計期間：6月25日〜7月3日）</b>
![twitter_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256115/ba38407f-8a95-9ca5-6118-527b1bc693a1.png)




###頻出ワードの可視化を行う

```python
df = df_tweet.copy()
df = df.dropna(subset=["text"])
import MeCab

m = MeCab.Tagger('-Ochasen  -d /usr/local/lib/mecab/dic/mecab-ipadic-neologd')
def word_analysis(doc):
    node = m.parseToNode(doc)
    word_list=[]
    while node:
        hinshi = node.feature.split(",")[0]
        if hinshi == "名詞":
          word_list.append(node.feature.split(",")[6])
        node = node.next
    return word_list

df["名詞"]=df["text"].apply(word_analysis)

import itertools
import collections
word_pickup = df["名詞"]
words =list( itertools.chain.from_iterable(word_pickup))
c = collections.Counter(words)

import seaborn as sns
import matplotlib.pyplot as plt

sns.set(font = "Hiragino Maru Gothic Pro",context="talk")
fig = plt.subplots(figsize=(10,30))
sns.countplot(y=words,order=[i[0] for i in c.most_common(50)])
```
<b>6月13日取得（集計期間：6月5日〜6月13日）</b>
![Twitter03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256115/b31ea34b-f175-0739-05b2-904167443f92.png)
<b>7月3日取得（集計期間：6月25日〜7月3日）</b>
![twitter3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256115/da123d81-3f99-1dca-194c-7dc50fe6dcdd.png)