web-dev-qa-db-ja.com

TweepyでTwitter APIの制限を回避する

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}]
28
4m1nh4j1

問題は、_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を発生させたときに、カーソルデータを更新していないために機能します。次回リクエストを行うとき、レート制限をトリガーしたリクエストと同じパラメーターを使用し、実際にそれが終了するまで繰り返します。

24
Aaron Hill

Googleでこれに遭遇した人のために、tweepy 3.2+には tweepy.api クラス用の追加パラメーターがあります。特に:

  • wait_on_rate_limit –レート制限が補充されるのを自動的に待つかどうか
  • wait_on_rate_limit_notify – Tweepyがレート制限の補充を待っているときに通知を印刷するかどうか

これらのフラグをTrueに設定すると、待機がAPIインスタンスに委任されます。これは、ほとんどの単純な使用例で十分です。

65
Dan Nguyen

エラーを回避し、レート制限を尊重したい場合は、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
17
Till Hoffmann

交換するだけ

api = tweepy.API(auth)

api = tweepy.API(auth, wait_on_rate_limit=True)
12
Mayank Khullar
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)
1
Malik Faiq