2014-01-23 2 views
22

В каком-то вопросе на Stack Exchange я заметил, что ограничение может быть функцией количества запросов за 15 минут и зависит также от сложности алгоритма, за исключением того, что это не сложный ,Избегайте ограничений API Twitter с помощью Tweepy

Поэтому я использую этот код:

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}] 
+0

возможный дубликат http://stackoverflow.com/questions/20559425/tweepy-python-rate-limit-exceeded-code-88 –

ответ

18

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

+0

Thank вы @Aaron, добавляет ли 'monitor_rate_limit = True, wait_on_rate_limit = True' вместо того, чтобы ловить исключения, работает с tweepy? – 4m1nh4j1

+4

'wait_on_rate_limit' остановит исключения. Tweepy будет спать, так как длительность необходима для того, чтобы лимит скорости пополнился. –

+0

@Aaron, как вы реализуете wait_on_rate_limit в коде aboce? – jxn

15

Если вы хотите избежать ошибок и соблюдать ограничение скорости, вы можете использовать следующую функцию, которая принимает ваш объект 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 
+0

Спасибо за этот ответ. Довольно полезно для работы с другим API, и я хотел бы уважать ограничение скорости :) –

+0

Обратите внимание, что в последней версии twavery функция 'getheader()' была заменена на 'headers' dict, поэтому' api.last_response.getheader ('x- limit-limit-limit ') 'необходимо заменить на' api.last_response.headers [' x-rate-limit-limit-Осталось '] ' – xro7

39

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

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

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

+0

Это должен быть принятый ответ. – DoesData

0

Просто замените

api = tweepy.API(auth) 

с

api = tweepy.API(auth, wait_on_rate_limit=True) 
Смежные вопросы