J'ai vu dans une question sur Stack Exchange que la limitation peut être fonction du nombre de demandes par 15 minutes et dépend également de la complexité de l'algorithme, sauf que ce n'est pas complexe.
J'utilise donc ce code:
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()
J'obtiens toujours l'erreur de limitation 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}]
Le problème est que votre bloc try: except:
Est au mauvais endroit. L'insertion de données dans la base de données ne soulèvera jamais un TweepError
- c'est une itération sur Cursor.items()
qui le fera. Je suggère de refactoriser votre code pour appeler la méthode next
de Cursor.items()
dans une boucle infinie. Cet appel doit être placé dans le bloc try: except:
, Car il peut déclencher une erreur.
Voici (grosso modo) à quoi devrait ressembler le code:
# 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
Cela fonctionne parce que lorsque Tweepy lève un TweepError
, il n'a mis à jour aucune des données du curseur. La prochaine fois qu'il fera la demande, il utilisera les mêmes paramètres que la demande qui a déclenché la limite de débit, la répétant effectivement jusqu'à ce qu'elle aille.
Pour toute personne qui tombe sur cela sur Google, tweepy 3.2+ a des paramètres supplémentaires pour la classe tweepy.api , en particulier:
wait_on_rate_limit
- Attendre ou non automatiquement que les limites de taux se reconstituentwait_on_rate_limit_notify
- Imprimer ou non une notification lorsque Tweepy attend que les limites de taux se reconstituentLa définition de ces indicateurs sur True
déléguera l'attente à l'instance d'API, ce qui est suffisant pour la plupart des cas d'utilisation simples.
Si vous voulez éviter les erreurs et respecter la limite de débit, vous pouvez utiliser la fonction suivante qui prend votre objet api
comme argument. Il récupère le nombre de demandes restantes du même type que la dernière demande et attend jusqu'à ce que la limite de débit soit réinitialisée si vous le souhaitez.
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
Il suffit de remplacer
api = tweepy.API(auth)
avec
api = tweepy.API(auth, wait_on_rate_limit=True)
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)