Evita la limitación de la API de Twitter con Tweepy

Vi en una pregunta en Stack Exchange que la limitación puede ser una función del número de solicitudes por 15 minutos y también depende de la complejidad del algoritmo, excepto que no es complejo.

Entonces uso este código:

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() 

Siempre me sale el error de limitación de Twitter:

 Traceback (most recent call last): File "stream.py", line 25, in  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}] 

El problema es que tu try: except: bloque está en el lugar equivocado. Insertar datos en la base de datos nunca TweepError un TweepError ; está iterando sobre Cursor.items() que lo hará. Yo sugeriría refactorizar su código para llamar al next método de Cursor.items() en un bucle infinito. Esa llamada debe colocarse en el try: except: bloque, ya que puede generar un error.

Aquí está (aproximadamente) cómo debe verse el código:

 # 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 

Esto funciona porque cuando Tweepy genera un TweepError , no ha actualizado ninguno de los datos del cursor. La próxima vez que realice la solicitud, utilizará los mismos parámetros que la solicitud que activó el límite de velocidad, repitiéndolo efectivamente hasta que pase.

Para cualquiera que se encuentre con esto en Google, tweepy 3.2+ tiene parámetros adicionales para la clase tweepy.api , en particular:

  • wait_on_rate_limit – Si esperar o no automáticamente a que se wait_on_rate_limit límites de velocidad
  • wait_on_rate_limit_notify – Si imprimir o no una notificación cuando Tweepy está esperando a que se repongan los límites de velocidad

Al establecer estos indicadores en True se delegará la espera en la instancia de API, lo cual es lo suficientemente bueno para los casos de uso más simples.

Si desea evitar errores y respetar el límite de velocidad, puede usar la siguiente función que toma su objeto api como argumento. Recupera el número de solicitudes restantes del mismo tipo que la última solicitud y espera hasta que el límite de velocidad se haya restablecido, si así lo desea.

 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 

Sólo reemplazar

 api = tweepy.API(auth) 

con

 api = tweepy.API(auth, wait_on_rate_limit=True)