tweepyで特定のツイートに対するリプライを取得する

## 1. 本記事について
本記事ではtweepyを使って特定のツイートと、およびそのツイートへのリプライのセットを取得するコードを記載します。
以下のコードでは、例として100件以上のリプライが投稿された
ツイートおよびリプライのデータを収集します。

取得したリプライと、宛先となっているツイートのセットは
ツイートデータの"id"列と、リプライデータの"in_reply_to_status_id"列を
照合することで紐づけが可能です。

なお、無料版のTwitter APIでは7日以上前のツイートは収集できない制限があります。

## 2. コード
```python:gather_tweets_and_reply.py
# coding:utf-8

import tweepy
import csv
import time
from datetime import datetime, date, timedelta
import re

# 現在の日付情報の取得
today = datetime.today()
# 取得するツイートの投稿時刻の範囲を指定(例：2日前から今日まで)
tweet_begin_date = datetime.strftime(today - timedelta(days=2), '%Y-%m-%d_00:00:00_JST')
tweet_end_date = datetime.strftime((today), '%Y-%m-%d_23:59:00_JST')
# 取得するリプライの投稿時刻の範囲を指定(例：2日前から今日まで)
reply_begin_date = datetime.strftime(today - timedelta(days=2), '%Y-%m-%d_00:00:00_JST')
reply_end_date = datetime.strftime((today), '%Y-%m-%d_23:59:00_JST')

# ツイート収集時の検索文字列を指定
tweet_query = "lang:ja exclude:retweets min_replies:100"
# リプライ収集時の検索文字列を指定
reply_query = "lang:ja filter:replies exclude:retweets"

# 取得結果csvファイル出力先ディレクトリ
csv_dir = '/hoge/'

# Twitter API KEY
Consumer_key = 'xxxx'
Consumer_secret = 'xxxx'
Access_token = 'xxxx'
Access_secret = 'xxxx'

# TwitterAPI認証用
def authTwitter():
        auth = tweepy.OAuthHandler(Consumer_key, Consumer_secret)
        auth.set_access_token(Access_token, Access_secret)
        api = tweepy.API(auth, retry_count=3,retry_delay=40,retry_errors=set([401, 404, 500, 502, 503, 504]), wait_on_rate_limit = True, wait_on_rate_limit_notify=True)
        return(api)

# ツイート&リプライデータ収集関数
def gather_tweet_and_reply(tweet_query,reply_query,tweet_begin_date,tweet_end_date,reply_begin_date,reply_end_date):
        api = authTwitter() # 認証
        tweet_list = []
        reply_list = []
        tweet_id_list = set()
        user_id_list = set()

        # ツイートを収集
        tweets = tweepy.Cursor(api.search, q = tweet_query,  # 検索文字列
                 include_entities = True,   # 省略されたリンクを全て取得
                 tweet_mode = 'extended',   # 省略されたツイートを全て取得
                 since = tweet_begin_date,  # 収集開始日時の指定
                 until = tweet_end_date,    # 収集終了期間の指定
                 lang = 'ja').items()       # 日本のツイートのみ取得

        # 検索したツイートをリストに格納
        for tweet in tweets:
                tweet_list.append([tweet.id, tweet.user.screen_name, tweet.created_at, tweet.full_text.replace('\n',''), tweet.favorite_count, tweet.retweet_count])
                tweet_id_list.add(tweet.id)
                user_id_list.add(tweet.user.screen_name)

        # user_id_listに格納されているユーザー名が宛先のリプライを検索
        for user_id in user_id_list:
                replies = tweepy.Cursor(api.search, q = reply_query + " to:" + str(user_id),   # 検索文字列
                          include_entities = True,   # 省略されたリンクを全て取得
                          tweet_mode = 'extended',   # 省略されたツイートを全て取得
                          since = reply_begin_date,    # リプライ収集開始日時の指定
                          until = reply_end_date,      # リプライ収集終了日時の指定
                          lang = 'ja').items()       # 日本のツイートのみ取得
                # リクエストの大量送信によるセッション切断対策
                time.sleep(5)
                # リプライの宛先IDが収集済ツイートIDと一致したらリストに格納
                for reply in replies:
                        if reply.in_reply_to_status_id in tweet_id_list:
                                reply_list.append([reply.id, reply.in_reply_to_status_id, reply.user.screen_name, reply.created_at, reply.full_text.replace('\n',''), reply.favorite_count, reply.retweet_count])

        # 結果をcsv出力
        with open(csv_dir + 'tweet_' + today.strftime('%Y%m%d_%H%M%S') + '.csv', 'w',newline='',encoding='utf-8') as f:
                writer = csv.writer(f, lineterminator='\n')
                writer.writerow(["id","user","created_at","text","fav","RT"])
                writer.writerows(tweet_list)
        pass

        with open(csv_dir + 'reply_' + today.strftime('%Y%m%d_%H%M%S') + '.csv', 'w',newline='',encoding='utf-8') as f:
                writer = csv.writer(f, lineterminator='\n')
                writer.writerow(["id","to_id","user","created_at","text","fav","RT"])
                writer.writerows(reply_list)
        pass

# ツイートデータを収集
def main():
        gather_tweet_and_reply(tweet_query, reply_query, tweet_begin_date, tweet_end_date, reply_begin_date, reply_end_date)

if __name__ == "__main__":
        main()

```
## 3. 参考
・[Twitter API 登録 (アカウント申請方法) から承認されるまでの手順まとめ　※2019年8月時点の情報 ](https://qiita.com/kngsym2018/items/2524d21455aac111cdee "Twitter API 登録 (アカウント申請方法) から承認されるまでの手順まとめ　※2019年8月時点の情報 ")
・[Tweepyのstatusリストで何が取れるのかわからなかったので、取り出してみた ](https://qiita.com/Ryo87/items/61b5d54cbfd7ae520fe6 "Tweepyのstatusリストで何が取れるのかわからなかったので、取り出してみた")