TwitterAPIの上限までTweetを取得する｜つぶやきをWordcloudで可視化①

私事ではありますが、2020年5月にコーギーという中型犬をお迎えしました。
<b>[愛犬のブログ](https://corgi-komugi.com/)</b>を運営してますので、見てもらえると嬉しいです。

<img width="400" alt="corgi_komugi" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/522259/fedf5812-0a89-947a-362b-b5dccb5b068a.jpeg">

<b>「コーギー関連のツイートをwordcloudで可視化したい！」</b>と思い立ち、以下の4項目を実施しました。

1. TwitterAPIでツイートを取得 ← 今回
2. [正規表現を用いてツイートを整形](https://qiita.com/komugi_papa/items/9b21cc0b5c612b5c0521)
3. [SudachiPyで形態素単位に分割](https://qiita.com/komugi_papa/items/7d04e386550406371ec5)
4. [WordCloudで可視化](https://qiita.com/komugi_papa/items/8b0cbe1f2674ed54040b)

⇒ <b>[一連のコードと様々なアウトプットの表示](https://corgi-komugi.com/twitter_wordcloud/)</b>

今回は、<b>「TwitterAPIでツイートを取得」</b>に関して説明していきます。

## 2021年12月30日
コードを一部修正しました。

## 対象者

- TwitterAPIのsearch apiでツイートを取得するために、コードを書きたい人
- TwitterAPIで取得したツイートを、pandasのデータフレームに変換したい人
- TwitterAPIのsearch apiのリクエストの上限に困っている人

なお、consumer_key,consumer_secret,access_token,access_secret の4つは、すでに取得できている前提で話を進めます。

## ざっくりとした要件定義
Input ... 「Twitter検索のためのクエリ」と「APIキー各種」
Output ... 以下の6つを列に含む、17,500ツイートのDataFrame


Outputに含まれる要素は、「ツイート番号」「ユーザーネーム」「ツイート時刻」「ツイートのテキスト」「いいねの数」「リツイートの数」になります。

![2021-07-12_22h36_16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/522259/f5735792-4caf-98ee-0780-96c13b2d9e52.png)


## コード
### コード全体

```python
import tweepy
import pandas as pd
import datetime

# Setting 280 characters in a column
pd.set_option("display.max_colwidth", 280)


def get_api_value(consumer_key,consumer_secret,access_token,access_secret):
    auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
    auth.set_access_token(access_token, access_secret)
    api = tweepy.API(auth)
    return api


def collect_tweet_data(q, api):
    '''
    ツイッターAPIを使用してデータを収集し、リストを作成する関数
    15分で180リクエストという制限があり、理論上は18,000ツイートが取得可能だが、
    たまに180リクエストで18,000ツイート取得できずエラーが発生するため、
    17500ツイートを取得するよう指定
    '''
    
    tweet_data = []

    for tweet in tweepy.Cursor(api.search_tweets, q=q, result_type='recent', count=100).items(17500):
        tweet_data.append([tweet.id_str,
                           tweet.user.screen_name,
                           tweet.created_at+datetime.timedelta(hours=9),
                           tweet.text.replace('\n',''),
                           tweet.favorite_count,tweet.retweet_count])
                
    return tweet_data

def create_tweets_df(q,api):
    tweet_data = collect_tweet_data(q=q,api=api)
    # 取得する列名を定義する
    columns_name=["TW_NO","USER_NAME","TW_TIME","TW_TEXT","FAV","RT"]
    df=pd.DataFrame(tweet_data,columns=columns_name)
    return df

# 自身で取得した値を代入してください。
consumer_key = 'xxxxxxxxxxxxx'
consumer_secret = 'xxxxxxxxxxxxxxx'
access_token = 'xxxxxxxxxxx'
access_secret = 'xxxxxxxxxxxxxx'

api=get_api_value(consumer_key,consumer_secret,access_token,access_secret)

q = f"#コーギー OR コーギー exclude:retweets -filter:replies"
df = create_tweets_df(q, api)
```

### コードの解説

<b>まず、事前に取得したキーから、apiにアクセスできるようにします。</b>

```python
def get_api_value(consumer_key,consumer_secret,access_token,access_secret):
    auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
    auth.set_access_token(access_token, access_secret)
    api = tweepy.API(auth)
    return api
```
<br>
<b>次に、リストでツイートのデータを取得します。</b>

api.searchは15分間で180リクエストを送信することが可能です。
count=100とすることで1リクエストあたり100ツイートを取得できるため、最大で18,000ツイートを1度に取得できます。
しかし、18,000ツイート取得しようとすると180リクエストでは取得できずにエラーを吐いてしまうこともあるので、17,500ツイートの取得にしました。

また、api.searchではjsonフォイルを取得できるため、jsonファイルから必要な情報を抜き出し、リストに加えていきます。


```python
def collect_tweet_data(q, api):
    '''
    ツイッターAPIを使用してデータを収集し、リストを作成する関数
    15分で180リクエストという制限があり、理論上は18,000ツイートが取得可能だが、
    たまに180リクエストで18,000ツイート取得できずエラーが発生するため、
    17500ツイートを取得するよう指定
    '''
    
    tweet_data = []

    for tweet in tweepy.Cursor(api.search_tweets, q=q, result_type='recent', count=100).items(17500):
        tweet_data.append([tweet.id_str,
                           tweet.user.screen_name,
                           tweet.created_at+datetime.timedelta(hours=9),
                           tweet.text.replace('\n',''),
                           tweet.favorite_count,tweet.retweet_count])
                
    return tweet_data
```
残りのリクエスト数が気になる場合は、こちらのコードで確認できます。

```python
#input
print("API.search")
print(api.rate_limit_status()["resources"]["search"]["/search/tweets"])
```

```python
#output
API.search
{'limit': 180, 'remaining': 170, 'reset': 1626095196}
```
これは、上限が180リクエストで、残りが170という意味になります。
<br>
<b>最後に、リストのデータをDataFrameに格納します。</b>

```python
def create_tweets_df(q,api):
    tweet_data = collect_tweet_data(q=q,api=api)
    # 取得する列名を定義する
    columns_name=["TW_NO","USER_NAME","TW_TIME","TW_TEXT","FAV","RT"]
    df=pd.DataFrame(tweet_data,columns=columns_name)
    return df
```

<br>
<b>これら3つの関数を用いて各種apiキーとクエリを以下のように入力すると、ツイートの情報が含まれたDataFrameを取得できます。</b>

```python
# 自身で取得した値を代入してください。
consumer_key = 'xxxxxxxxxxxxx'
consumer_secret = 'xxxxxxxxxxxxxxx'
access_token = 'xxxxxxxxxxx'
access_secret = 'xxxxxxxxxxxxxx'

api=get_api_value(consumer_key,consumer_secret,access_token,access_secret)

q = f"#コーギー exclude:retweets -filter:replies"
df = create_tweets_df(q, api)
```

outputは以下の通りです。

![2021-07-12_22h36_16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/522259/f5735792-4caf-98ee-0780-96c13b2d9e52.png)

##まとめ
この記事では、TwitterAPIでツイートを取得するコードを見ていきました。

次は、正規表現を用いてツイートの形を整えたいと思います。
[こちらの記事](https://qiita.com/komugi_papa/items/9b21cc0b5c612b5c0521)で説明してますので、興味があれば見てもらえると嬉しいです。


<img width="400" alt="corgi_komugi" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/522259/1b3f0447-f365-50ee-9e96-ac3134ffad25.jpeg">

##参考文献
[twitterのデータ探索に関わるtweepyの基本機能の解説](https://akitoshiblogsite.com/tweepy-basic-functions/#toc16)
[【2021年7月執筆】Twitterでのsearch APIの制約について](https://qiita.com/komugi_papa/items/8abde502fedd0a1e9c56)