1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Posted at

開発環境:MacOS
使用言語:Python3.7(3.6以前でも実行可能)
TwitterAPIで取得できる情報にはツイートに対するリプライ取得などが公式で準備されていないので自作
特定のユーザもしくはツイートに対するリプライを取得してpandasでcsvファイルに保存
実行に必要なモジュールは大体pip installpip3 installでインストールできます。
※TwitterAPIの利用には認証キーが必要です。登録の方法などはこちらを参考にしました。

get_replies.py
from requests_oauthlib import OAuth1Session
import json
import datetime, time, sys
import codecs
import pandas as pd
from collections import defaultdict
CK = ''    # Consumer Keyを入れてください
CS = ''    # Consumer Secretを入れてください
AT = ''    # Access Tokenを入れてください
AS = ''    # Accesss Token Secretを入れてください
session = OAuth1Session(CK, CS, AT, AS)

url = 'https://api.twitter.com/1.1/search/tweets.json?'

TweetList = defaultdict(list)

def get_replies(to_user, since_id):
    N = 5 #繰り返しの数
    query = " -rt to:" + to_user
    lang = "ja"
    result_type="recent" # 最新のツイートを取得
    count = 100 # 1回あたりの最大取得ツイート数(最大100)
    max_id = ''
    for i in range(N):
        params = {
                    'q':query,
                    'lang':lang,
                    'count':count,
                    'since_id':since_id,
                    'max_id':max_id
                 }
        res = session.get(url, params = params)

        if res.status_code != 200:
            print ("Twitter API Error: %d" % res.status_code)
            sys.exit(1)

        limit = int(res.headers['X-Rate-Limit-Remaining'])
        print ('アクセス可能回数 %d' % limit)
        print ('リセット時間 %s' % res.headers['X-Rate-Limit-Reset'])
        sec = int(res.headers['X-Rate-Limit-Reset'])\
            - time.mktime(datetime.datetime.now().timetuple())
        print ('リセット時間 (残り秒数に換算) %s' % sec)
        if limit < 2:
            print("リセット時間まで待機します\n残り時間:%s" % abs(sec))
            time.sleep(abs(sec))

        res_text = json.loads(res.text)
        for tweet in res_text['statuses']:
            # 最後のidを格納
            max_id = str(tweet['id']-1)

            try:
                if(since_id not in tweet['in_reply_to_status_id_str']):
                    continue
            except:
                print('リプライの取得に失敗したか、このツイートはリプライではありません')
                continue
            print('--------------------------------------')
            print ('[作成日時]\n %s' % tweet['created_at'])
            print ('[内容]\n %s' % tweet['text'])
            print ('[ユーザー]\n %s' % tweet['user']['screen_name'])
            print ('[ID]\n %s' % tweet['id_str'])
            print ('[リプライ先ID]\n %s' % tweet['in_reply_to_status_id_str'])
            print('--------------------------------------')
            print ('\n')

            TweetList['id'].append(tweet['id'])
            TweetList['name'].append(tweet['user']['screen_name'])
            TweetList['created_at'].append(tweet['created_at'])
            TweetList['retweet_count'].append(tweet['retweet_count'])
            TweetList['favorite_count'].append(tweet['favorite_count'])
            TweetList['in_reply_to_status_id_str'].append(tweet['in_reply_to_status_id_str'])
            TweetList['text'].append(tweet['text'])

        print('%d回目のループ終了\n'%(i+1))

    df = pd.DataFrame(TweetList)
    now = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
    new_filename = "./"+to_user+"_replies"+now+".csv"
    df.to_csv(new_filename,encoding='utf-8-sig')
    TweetList.clear()

if __name__ == '__main__':
    get_replies('TwitterJP','')

実行するとカレントディレクトリにTwitterJP_replies2019010120574.csv(後ろの数字は作成した年月日時分秒)のようなcsvファイルが生成されていると思います。

関数の引数は以下のようになっています。
第1引数: リプライ元のユーザ名
第2引数: リプライ元のツイートのID(str型)

第2引数は例のように空でも構いませんが、その場合は指定したユーザーの複数のツイートに対するリプライを取得することになります。

リプライ取得の仕組み

Twitter REST APIのGET/Search Tweetsを利用しました。公式サイトはこちら

はじめにも書きましたが、TwitterAPIには直接リプライを取得するメソッドはありません。その代わり、取得できる情報に'in_reply_to_status_id'という項目があって、これはツイートがリプライだった場合、リプライ先のツイートのIDが入っています。
つまり、ツイートAのリプライが欲しいとして、ツイートBを取得した時、
ツイートAのIDと取得したツイートBの'in_reply_to_status_id'を比較して一致していれば、ツイートBはツイートAのリプライであると分かるのです。

ソースコードの

try:
    if(since_id not in tweet['in_reply_to_status_id_str']):
        continue

が比較を行っている部分になります。取得したツイートがリプライでない(引用RTなど)場合には、そもそも'in_reply_to_status_id_str'の項目が存在せず、エラーが発生するのでtry:の中に入れてあります。

また、paramsの'q'ではツイートの条件指定が可能です(こちらを参考にしました)。これを利用すると、to:ユーザ名 を検索クエリに含めることで特定のアカウントに対するツイートのみを取得することができます。この中からリプライを探し出すわけですね。

Search/tweetsでは1回のリクエストで最大100件のツイートを取得可能です。for文で回すことで100×N個のツイートを取得するようにしています(そんな数のリプライが付くツイートはなかなかないと思いますが)。ただし、15分で180回までしかリクエストできないのでアクセス可能回数が残り1になったらリセット時間までtime.sleep()で待機するようにしています。

注意点

search/tweetsの仕様として、Standard APIでは1週間前までのツイートしか取得することができません。1ヶ月前のツイートに対するリプライを取得しようとか思ったら別の方法が必要になると思います。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?