Stack Exchangeに関する質問で、制限は15分あたりのリクエスト数の関数であり、アルゴリズムの複雑さにも依存することがわかりましたが、これは複雑なものではありません。
だから私はこのコードを使用します:
import tweepy
import sqlite3
import time
db = sqlite3.connect('data/MyDB.db')
# Get a cursor object
cursor = db.cursor()
cursor.execute('''CREATE TABLE IF NOT EXISTS MyTable(id INTEGER PRIMARY KEY, name TEXT, geo TEXT, image TEXT, source TEXT, timestamp TEXT, text TEXT, rt INTEGER)''')
db.commit()
consumer_key = ""
consumer_secret = ""
key = ""
secret = ""
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(key, secret)
api = tweepy.API(auth)
search = "#MyHashtag"
for Tweet in tweepy.Cursor(api.search,
q=search,
include_entities=True).items():
while True:
try:
cursor.execute('''INSERT INTO MyTable(name, geo, image, source, timestamp, text, rt) VALUES(?,?,?,?,?,?,?)''',(Tweet.user.screen_name, str(Tweet.geo), Tweet.user.profile_image_url, Tweet.source, Tweet.created_at, Tweet.text, Tweet.retweet_count))
except tweepy.TweepError:
time.sleep(60 * 15)
continue
break
db.commit()
db.close()
Twitterの制限エラーが常に表示されます。
Traceback (most recent call last):
File "stream.py", line 25, in <module>
include_entities=True).items():
File "/usr/local/lib/python2.7/dist-packages/tweepy/cursor.py", line 153, in next
self.current_page = self.page_iterator.next()
File "/usr/local/lib/python2.7/dist-packages/tweepy/cursor.py", line 98, in next
data = self.method(max_id = max_id, *self.args, **self.kargs)
File "/usr/local/lib/python2.7/dist-packages/tweepy/binder.py", line 200, in _call
return method.execute()
File "/usr/local/lib/python2.7/dist-packages/tweepy/binder.py", line 176, in execute
raise TweepError(error_msg, resp)
tweepy.error.TweepError: [{'message': 'Rate limit exceeded', 'code': 88}]
問題は、_try: except:
_ブロックが間違った場所にあることです。データベースにデータを挿入しても、TweepError
が発生することはありません-Cursor.items()
を繰り返し処理します。無限ループでCursor.items()
のnext
メソッドを呼び出すようにコードをリファクタリングすることをお勧めします。エラーが発生する可能性があるため、その呼び出しは_try: except:
_ブロックに配置する必要があります。
コードは次のようになります(おおよそ)。
_# above omitted for brevity
c = tweepy.Cursor(api.search,
q=search,
include_entities=True).items()
while True:
try:
Tweet = c.next()
# Insert into db
except tweepy.TweepError:
time.sleep(60 * 15)
continue
except StopIteration:
break
_
これは、TweepyがTweepError
を発生させたときに、カーソルデータを更新していないために機能します。次回リクエストを行うとき、レート制限をトリガーしたリクエストと同じパラメーターを使用し、実際にそれが終了するまで繰り返します。
Googleでこれに遭遇した人のために、tweepy 3.2+には tweepy.api クラス用の追加パラメーターがあります。特に:
wait_on_rate_limit
–レート制限が補充されるのを自動的に待つかどうかwait_on_rate_limit_notify
– Tweepyがレート制限の補充を待っているときに通知を印刷するかどうかこれらのフラグをTrue
に設定すると、待機がAPIインスタンスに委任されます。これは、ほとんどの単純な使用例で十分です。
エラーを回避し、レート制限を尊重したい場合は、api
オブジェクトを引数として使用する次の関数を使用できます。残りのリクエストの数を取得します最後のリクエストと同じタイプ。必要に応じてレート制限がリセットされるまで待機します。
def test_rate_limit(api, wait=True, buffer=.1):
"""
Tests whether the rate limit of the last request has been reached.
:param api: The `tweepy` api instance.
:param wait: A flag indicating whether to wait for the rate limit reset
if the rate limit has been reached.
:param buffer: A buffer time in seconds that is added on to the waiting
time as an extra safety margin.
:return: True if it is ok to proceed with the next request. False otherwise.
"""
#Get the number of remaining requests
remaining = int(api.last_response.getheader('x-rate-limit-remaining'))
#Check if we have reached the limit
if remaining == 0:
limit = int(api.last_response.getheader('x-rate-limit-limit'))
reset = int(api.last_response.getheader('x-rate-limit-reset'))
#Parse the UTC time
reset = datetime.fromtimestamp(reset)
#Let the user know we have reached the rate limit
print "0 of {} requests remaining until {}.".format(limit, reset)
if wait:
#Determine the delay and sleep
delay = (reset - datetime.now()).total_seconds() + buffer
print "Sleeping for {}s...".format(delay)
sleep(delay)
#We have waited for the rate limit reset. OK to proceed.
return True
else:
#We have reached the rate limit. The user needs to handle the rate limit manually.
return False
#We have not reached the rate limit
return True
交換するだけ
api = tweepy.API(auth)
と
api = tweepy.API(auth, wait_on_rate_limit=True)
import tweepy
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)
# will notify user on ratelimit and will wait by it self no need of sleep.
api = tweepy.API(auth, wait_on_rate_limit=True, wait_on_rate_limit_notify=True)