Подтвердить что ты не робот

Избегайте ограничений API Twitter с помощью Tweepy

В каком-то вопросе на 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}]
4b9b3361

Ответ 1

Проблема в том, что ваш блок try: except: находится в неправильном месте. Вставка данных в базу данных никогда не приведет к увеличению TweepError - итерации по Cursor.items(), которые будут. Я бы предложил рефакторинг вашего кода, чтобы вызвать метод next Cursor.items() в бесконечном цикле. Этот вызов должен быть помещен в блок 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, он не обновил ни одного из данных курсора. В следующий раз, когда он сделает запрос, он будет использовать те же параметры, что и запрос, который вызвал ограничение скорости, эффективно повторяя его до тех пор, пока он не пройдет.

Ответ 2

Для всех, кто наткнулся на это в Google, tweepy 3.2+ имеет дополнительные параметры для класса tweepy.api, в частности:

  • wait_on_rate_limit - Независимо от того, будете ли вы автоматически ждать ограничения скорости, чтобы пополнить
  • wait_on_rate_limit_notify - следует ли распечатать уведомление, когда Tweepy ожидает, чтобы ограничения по скорости были пополнены.

Установка этих флагов в True будет делегировать ожидание экземпляру API, что достаточно хорошо для большинства простых случаев использования.

Ответ 3

Если вы хотите избежать ошибок и соблюдать ограничение скорости, вы можете использовать следующую функцию, которая принимает ваш объект api в качестве аргумента. Он извлекает количество оставшихся запросов того же типа, что и последний запрос, и ждет, пока ограничение скорости будет reset, если это необходимо.

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