python - bot - tweepy tutorial
Evitar la limitaciĆ³n de Twitter API con Tweepy (4)
Vi en alguna 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 recibo el error de limitación de 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}]
El problema es que su try: except:
bloqueo está en el lugar equivocado. Insertar datos en la base de datos nunca TweepError
un TweepError
; se Cursor.items()
sobre Cursor.items()
. 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:
bloquear, ya que puede generar un error.
Aquí está (más o menos) cómo debería 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 desencadenó el límite de frecuencia, repitiéndolo de manera efectiva hasta que finalice.
Para cualquiera que se tropiece con esto en Google, tweepy 3.2+ tiene parámetros adicionales para la clase tweepy.api , en particular:
-
wait_on_rate_limit
: si se espera o no automáticamente los límites de velocidad para reponer -
wait_on_rate_limit_notify
- Si se imprime o no una notificación cuando Tweepy está esperando que se carguen los límites de la tasa
Establecer estos indicadores en True
delegará la espera a la instancia de la API, que es lo suficientemente buena para la mayoría de los casos de uso simple.
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 se haya restablecido el límite de velocidad 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
Simplemente reemplace
api = tweepy.API(auth)
con
api = tweepy.API(auth, wait_on_rate_limit=True)