質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

0回答

486閲覧

PythonでTwitterのツイートを取得したい

gymgym

総合スコア97

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2018/07/19 08:09

PythonでTwitterのツイートを取得しようと考えています。

その際には、制限があるのでその制限ギリギリまでツイートを取得したいです。

現在、以下のようなコードを用いています。
参考:http://ailaby.com/twitter_api/

Python

1# -*- coding: utf-8 -*- 2 3from requests_oauthlib import OAuth1Session 4import json 5import datetime 6import time 7import sys 8import csv 9import config 10from abc import ABCMeta, abstractmethod 11 12CK = config.CONSUMER_KEY 13CS = config.CONSUMER_SECRET 14AT = config.ACCESS_TOKEN 15AS = config.ACCESS_TOKEN_SECRET 16 17class TweetsGetter(object): 18 __metaclass__ = ABCMeta 19 20 def __init__(self): 21 self.session = OAuth1Session(CK, CS, AT, AS) 22 23 @abstractmethod 24 def specifyUrlAndParams(self, keyword): 25 ''' 26 呼出し先 URL、パラメータを返す 27 ''' 28 29 @abstractmethod 30 def pickupTweet(self, res_text, includeRetweet): 31 ''' 32 res_text からツイートを取り出し、配列にセットして返却 33 ''' 34 35 @abstractmethod 36 def getLimitContext(self, res_text): 37 ''' 38 回数制限の情報を取得 (起動時) 39 ''' 40 41 def collect(self, total=-1, onlyText=False, includeRetweet=False): 42 ''' 43 ツイート取得を開始する 44 ''' 45 46 #---------------- 47 # 回数制限を確認 48 #---------------- 49 self.checkLimit() 50 51 #---------------- 52 # URL、パラメータ 53 #---------------- 54 url, params = self.specifyUrlAndParams() 55 params['include_rts'] = str(includeRetweet).lower() 56 # include_rts は statuses/user_timeline のパラメータ。search/tweets には無効 57 58 #---------------- 59 # ツイート取得 60 #---------------- 61 cnt = 0 62 unavailableCnt = 0 63 while True: 64 res = self.session.get(url, params=params) 65 if res.status_code == 503: 66 # 503 : Service Unavailable 67 if unavailableCnt > 10: 68 raise Exception('Twitter API error %d' % res.status_code) 69 70 unavailableCnt += 1 71 print('Service Unavailable 503') 72 self.waitUntilReset(time.mktime( 73 datetime.datetime.now().timetuple()) + 30) 74 continue 75 76 unavailableCnt = 0 77 78 if res.status_code != 200: 79 raise Exception('Twitter API error %d' % res.status_code) 80 81 tweets = self.pickupTweet(json.loads(res.text)) 82 if len(tweets) == 0: 83 # len(tweets) != params['count'] としたいが 84 # count は最大値らしいので判定に使えない。 85 # ⇒ "== 0" にする 86 # https://dev.twitter.com/discussions/7513 87 break 88 89 for tweet in tweets: 90 if (('retweeted_status' in tweet) and (includeRetweet is False)): 91 pass 92 else: 93 if onlyText is True: 94 yield tweet['text'] 95 else: 96 yield tweet 97 98 cnt += 1 99 if cnt % 100 == 0: 100 print('%d件 ' % cnt) 101 102 if total > 0 and cnt >= total: 103 return 104 105 params['max_id'] = tweet['id'] - 1 106 107 # ヘッダ確認 (回数制限) 108 # X-Rate-Limit-Remaining が入ってないことが稀にあるのでチェック 109 if ('X-Rate-Limit-Remaining' in res.headers and 'X-Rate-Limit-Reset' in res.headers): 110 if (int(res.headers['X-Rate-Limit-Remaining']) == 0): 111 self.waitUntilReset(int(res.headers['X-Rate-Limit-Reset'])) 112 self.checkLimit() 113 else: 114 print('not found - X-Rate-Limit-Remaining or X-Rate-Limit-Reset') 115 self.checkLimit() 116 117 def checkLimit(self): 118 ''' 119 回数制限を問合せ、アクセス可能になるまで wait する 120 ''' 121 unavailableCnt = 0 122 while True: 123 url = "https://api.twitter.com/1.1/application/rate_limit_status.json" 124 res = self.session.get(url) 125 126 if res.status_code == 503: 127 # 503 : Service Unavailable 128 if unavailableCnt > 10: 129 raise Exception('Twitter API error %d' % res.status_code) 130 131 unavailableCnt += 1 132 print('Service Unavailable 503') 133 self.waitUntilReset(time.mktime( 134 datetime.datetime.now().timetuple()) + 30) 135 continue 136 137 unavailableCnt = 0 138 139 if res.status_code != 200: 140 raise Exception('Twitter API error %d' % res.status_code) 141 142 remaining, reset = self.getLimitContext(json.loads(res.text)) 143 if (remaining == 0): 144 self.waitUntilReset(reset) 145 else: 146 break 147 148 def waitUntilReset(self, reset): 149 ''' 150 reset 時刻まで sleep 151 ''' 152 seconds = reset - time.mktime(datetime.datetime.now().timetuple()) 153 seconds = max(seconds, 0) 154 print('\n =====================') 155 print(' == waiting %d sec ==' % seconds) 156 print(' =====================') 157 sys.stdout.flush() 158 time.sleep(seconds + 10) # 念のため + 10 秒 159 160 @staticmethod 161 def bySearch(keyword): 162 return TweetsGetterBySearch(keyword) 163 164 @staticmethod 165 def byUser(screen_name): 166 return TweetsGetterByUser(screen_name) 167 168 169class TweetsGetterBySearch(TweetsGetter): 170 ''' 171 キーワードでツイートを検索 172 ''' 173 174 def __init__(self, keyword): 175 super(TweetsGetterBySearch, self).__init__() 176 self.keyword = keyword 177 178 def specifyUrlAndParams(self): 179 ''' 180 呼出し先 URL、パラメータを返す 181 ''' 182 url = 'https://api.twitter.com/1.1/search/tweets.json' 183 #params = {'q': self.keyword, 'count': 100} 184 query = '任天堂 exclude:retweets since:2018-07-05' 185 params = { 186 'q': query, 'count': 100 187 } 188 189 return url, params 190 191 def pickupTweet(self, res_text): 192 ''' 193 res_text からツイートを取り出し、配列にセットして返却 194 ''' 195 results = [] 196 for tweet in res_text['statuses']: 197 results.append(tweet) 198 199 return results 200 201 def getLimitContext(self, res_text): 202 ''' 203 回数制限の情報を取得 (起動時) 204 ''' 205 remaining = res_text['resources']['search']['/search/tweets']['remaining'] 206 reset = res_text['resources']['search']['/search/tweets']['reset'] 207 208 return int(remaining), int(reset) 209 210 211class TweetsGetterByUser(TweetsGetter): 212 ''' 213 ユーザーを指定してツイートを取得 214 ''' 215 216 def __init__(self, screen_name): 217 super(TweetsGetterByUser, self).__init__() 218 self.screen_name = screen_name 219 220 def specifyUrlAndParams(self): 221 ''' 222 呼出し先 URL、パラメータを返す 223 ''' 224 url = 'https://api.twitter.com/1.1/statuses/user_timeline.json' 225 params = {'screen_name': self.screen_name, 'count': 200} 226 return url, params 227 228 def pickupTweet(self, res_text): 229 ''' 230 res_text からツイートを取り出し、配列にセットして返却 231 ''' 232 results = [] 233 for tweet in res_text: 234 results.append(tweet) 235 236 return results 237 238 def getLimitContext(self, res_text): 239 ''' 240 回数制限の情報を取得 (起動時) 241 ''' 242 remaining = res_text['resources']['statuses']['/statuses/user_timeline']['remaining'] 243 reset = res_text['resources']['statuses']['/statuses/user_timeline']['reset'] 244 245 return int(remaining), int(reset) 246 247 248if __name__ == '__main__': 249 250 # キーワードで取得 251 #getter = TweetsGetter.bySearch(u'任天堂') 252 253 # ユーザーを指定して取得 (screen_name) 254 getter = TweetsGetter.byUser('@fashionpressnet') 255 256 cnt = 0 257 f = open('test.csv', 'a') 258 for tweet in getter.collect(total=10000): 259 cnt += 1 260 tweet_list = [tweet['created_at'], tweet['text'], tweet['retweet_count'], tweet['favorite_count']] 261 writer = csv.writer(f, lineterminator='\n') # 行末は改行 262 writer.writerow(tweet_list) 263

以下の部分で、ツイートが10000件取得すると終了してしまう仕様となっているのですが、
制限ギリギリいっぱいまで取得できるようにしたいです。

Python

1 f = open('test.csv', 'a') 2 for tweet in getter.collect(total=10000): 3 cnt += 1 4 tweet_list = [tweet['created_at'], tweet['text'], tweet['retweet_count'], tweet['favorite_count']] 5 writer = csv.writer(f, lineterminator='\n') # 行末は改行 6 writer.writerow(tweet_list)

取得できる範囲で限界まで取得すると終了となるようにしたいのですが、どのようにしたら良いでしょうか。
よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問