Wie Sie wissen, ist die Anzahl der Tweets, die Sie in einem bestimmten Zeitraum erhalten, und die Anzahl der Tweets, die Sie gleichzeitig erhalten, begrenzt, wenn Sie Tweets mit der Twitter-API erhalten.
Um mit dieser Einschränkung gut umzugehen, finden Sie hier einige Tipps, wie Sie sie kontinuierlich erhalten können. Bitte beachten Sie, dass dieser Beitrag POST nicht abdeckt. (Obwohl es fast das gleiche ist)
Bitte überprüfen Sie die primären Informationen auf numerische Werte. Der Beispielcode lautet auf Gist veröffentlicht. (Ich habe gehört, dass es ein Twitter-Paket gibt, aber ich benutze es nicht.)
Die Grenzen sind wie folgt.
GET endpoints
The standard API rate limits described in this table refer to GET (read) endpoints. Note that endpoints not listed in the chart default to 15 requests per allotted user. All request windows are 15 minutes in length. These rate limits apply to the standard API endpoints only, does not apply to premium APIs.
Auszug aus Ratenlimits - Twitter-Entwickler
Die Anzahl der Akquisitionen in 15-Minuten-Einheiten ist begrenzt. Laut dieser Seite gelten beispielsweise die Einschränkungen für "Suche / Tweets" wie folgt (oh, Standard).
Auszug aus [Ratenlimits - Twitter-Entwickler](https://developer.twitter.com/de/docs/basics/rate-limits)
Endpoint Resource family Requests / window (user auth) Requests / window (app auth) GET search/tweets search 180 450
Den aktuellen Grenzwertstatus als Endpunkt erhalten Sie unter https://api.twitter.com/1.1/application/rate_limit_status.json. Der Parameter "Ressourcen" ist optional und gibt "Ressourcenfamilie" an.
user auth (OAuth v1.1)
{
"rate_limit_context": {
"access_token": "*******************"
},
"resources": {
"search": {
"/search/tweets": {
"limit": 180,
"remaining": 180,
"reset": 1591016735
}
}
}
}
app auth (OAuth v2.0)
{
"rate_limit_context": {
"application": "dummykey"
},
"resources": {
"search": {
"/search/tweets": {
"limit": 450,
"remaining": 450,
"reset": 1591016736
}
}
}
}
Jede der "Reset" -Nummern ist die Epochenzeit, die die zurückzusetzende Zeit angibt.
Im obigen Beispiel "Benutzerauthentifizierung" (OAuth v1.1) mit Epochenzeit "1591016735" = "2020-06-01 22: 05: 35", "Appauthentifizierung" (OAuth v2.0) mit "1591016736" = Zeigt an, dass es auf "2020-06-01 22: 05: 36" zurückgesetzt wird.
Wenn Sie das Limit überschreiten, lautet die Zahl für "verbleibend" "0".
Die Elemente der erfassten Informationen sind wie folgt. (Beispiel einer Suchfamilie)
Category | Family | Endpoint | Key | Value |
---|---|---|---|---|
rate_limit_context | access_token (user auth (v1.1)) | Inhalt des Zugriffstokens | ||
application (app auth (v2.0)) | dummykey (Scheint behoben zu sein) | |||
resources | ||||
search | ||||
/search/tweets | ||||
limit | Maximale Anzahl von Malen innerhalb des Zeitlimits | |||
remaining | Verbleibende Anzahl von Malen, auf die innerhalb des Zeitlimits zugegriffen werden kann | |||
reset | Zeitpunkt, zu dem das Zeitlimit zurückgesetzt wird(epoch time) |
Das folgende Beispiel ist, wenn Sie fälschlicherweise "Benutzer" für die Ressourcenfamilie angeben. (Eigentlich sollten Sie "Benutzer" (mit s) angeben.)
user auth
{
"rate_limit_context": {
"access_token": "*******************"
}
}
app auth
{
"rate_limit_context": {
"application": "dummykey"
}
}
Beide geben " rate_limit_context
"zurück, haben aber keine" resources
".
Wenn ein Ratenlimitfehler auftritt, wird 429 in "res.status_code" (HTTP-Statuscode) zurückgegeben. (420 können zurückgegeben werden [^ 1].)
[^ 1]: Im Allgemeinen wird 429 "Zu viele Anfragen: Wird zurückgegeben, wenn eine Anfrage nicht bearbeitet werden kann, weil das Ratenlimit der App für die Ressource erschöpft ist. "" Wird zurückgegeben, in seltenen Fällen jedoch 420 "Enhance Your Ruhe: Wird zurückgegeben, wenn die Rate einer App für zu viele Anfragen begrenzt ist.
" Kann zurückgegeben werden. Letzteres kann passieren, wenn Sie versehentlich mehrere Anfragen gleichzeitig stellen (nicht überprüft). → In "Herstellen einer Verbindung zu einem Streaming-Endpunkt - Twitter-Entwickler" wurde eine Erklärung hinzugefügt, die ich dem Text hinzufügte. (2020/06/03).
Auszug aus [Antwortcodes - Twitter-Entwickler](https://developer.twitter.com/de/docs/basics/response-codes)
Code Text Description 420 Enhance Your Calm Returned when an app is being rate limited for making too many requests. 429 Too Many Requests Returned when a request cannot be served due to the app's rate limit having been exhausted for the resource. See Rate Limiting.
[Aktualisiert am 06/03/2020] Es gab eine detaillierte Erklärung von 420 unten.
Auszug aus [Verbindung zu einem Streaming-Endpunkt herstellen - Twitter-Entwickler](https://developer.twitter.com/de/docs/tweets/filter-realtime/guides/connecting)
420 Rate Limited The client has connected too frequently. For example, an endpoint returns this status if:
- A client makes too many login attempts in a short period of time.
- Too many copies of an application attempt to authenticate with the same credentials.
88 wird in den JSON-Fehlercode eingegeben.
{
"errors": [
{
"code": 88,
"message": "Rate limit exceeded"
}
]
}
Auszug aus [Antwortcodes - Twitter-Entwickler](https://developer.twitter.com/de/docs/basics/response-codes)
Code Text Description 88 Rate limit exceeded Corresponds with HTTP 429. The request limit for this resource has been reached for the current rate limit window.
Ausnahmen wie "Anfragen" finden Sie auf jeder Website.
Berücksichtigt der Verarbeitungsablauf das Ratenlimit wie folgt?
while True:
try:
res =Anfrage an API erhalten/post
res.raise_for_status()
except requests.exceptions.HTTPError:
#429 wenn das Ratenlimit erreicht ist/420 wird zurückgegeben
if res.status_code in (420, 429):
Informationen zum Ratenlimit erhalten ← Hier
Warten Sie ruhig bis zum Zurücksetzen
continue
420/Andere Ausnahmebehandlung als 429
except OtherException:
Ausnahmebehandlung
Verarbeitung, wenn es erfolgreich erworben werden kann
brechen oder zurückkehren oder nachgeben etc.
Das Folgende ist eine konkrete Maßnahme für den Teil "Get Rate Limit Information".
Als Beispiel für die Informationserfassung gibt es nicht viel Verdienst, sie in einer Klasse zu implementieren, aber wenn man bedenkt, dass sie tatsächlich in ein Programm integriert wird, ist es meiner Meinung nach besser, sie in einer Form zu schreiben, die einfach zu modularisieren ist. Deshalb habe ich sie zu einer Klasse namens GetTweetStatus gemacht. Es gibt. (Es besteht auch der Wunsch, den Zugriff von außen wie Apikey und Bearer so weit wie möglich zu vermeiden ...)
class GetTweetStatus
def __init__(self, apikey, apisec, access_token="", access_secret=""):
self._apikey = apikey
self._apisec = apisec
self._access_token = access_token
self._access_secret = access_secret
self._access_token_mask = re.compile(r'(?P<access_token>"access_token":)\s*".*"')
Die letzte Zeile, re.compile (), dient zum Maskieren der Anzeige des empfangenen "access_token".
user auth (OAuth v1.1)
GetTweetStatus.get_limit_status_v1( )
def get_limit_status_v1(self, resource_family="search"):
"""OAuth v1.Erhalten Sie den Status mit 1"""
#Verwenden Sie OAuth1Session, da OAuth kompliziert ist
oauth1 = OAuth1Session(self._apikey, self._apisec, self._access_token, self._access_secret)
params = {
'resources': resource_family # help, users, search, statuses etc.
}
try:
res = oauth1.get(STATUS_ENDPOINT, params=params, timeout=5.0)
res.raise_for_status()
except (TimeoutError, requests.ConnectionError):
raise requests.ConnectionError("Cannot get Limit Status")
except Exception:
raise Exception("Cannot get Limit Status")
return res.json()
request_oauthlib
und from request_oauthlib import OAuth1Session
installieren.app auth (OAuth v2.0)
GetTweetStatus.get_limit_status_v2( )
def get_limit_status_v2(self, resource_family="search"):
"""OAuth v2.0 (Bearer)Status abrufen mit"""
bearer = self._get_bearer() #Holen Sie sich Träger
headers = {
'Authorization':'Bearer {}'.format(bearer),
'User-Agent': USER_AGENT
}
params = {
'resources': resource_family # help, users, search, statuses etc.
}
try:
res = requests.get(STATUS_ENDPOINT, headers=headers, params=params, timeout=5.0)
res.raise_for_status()
except (TimeoutError, requests.ConnectionError):
raise requests.ConnectionError("Cannot get Limit Status")
except Exception:
raise Exception("Cannot get Limit Status")
return res.json()
bearer = self._get_bearer () Dies ist der
_get_bearer () Teil, der von #Get Bearer
aufgerufen wird.
GetTweetStatus._get_bearer( ), _get_credential( )
def _get_bearer(self):
"""Holen Sie sich Träger"""
cred = self._get_credential()
headers = {
'Authorization': 'Basic ' + cred,
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
'User-Agent': USER_AGENT
}
data = {
'grant_type': 'client_credentials',
}
try:
res = requests.post(TOKEN_ENDPOINT, data=data, headers=headers, timeout=5.0)
res.raise_for_status()
except (TimeoutError, requests.ConnectionError):
raise Exception("Cannot get Bearer")
except requests.exceptions.HTTPError:
if res.status_code == 403:
raise requests.exceptions.HTTPError("Auth Error")
raise requests.exceptions.HTTPError("Other Exception")
except Exception:
raise Exception("Cannot get Bearer")
rjson = res.json()
return rjson['access_token']
def _get_credential(self):
"""Anmeldeinformationen generieren"""
pair = self._apikey + ':' + self._apisec
bcred = b64encode(pair.encode('utf-8'))
return bcred.decode()
access_token
"des zurückgegebenen JSON gesetzt, also holen Sie es sich.Es ist als Methode implementiert. Ist es ein Ort, um etwas zu implementieren, das "reset" zurückgibt, wenn es tatsächlich verwendet wird?
GetTweetStatus.disp_limit_status( )
def disp_limit_status(self, version=2, resource_family="search"):
"""Anzeigenlimit nach Version"""
if version == 2:
resj = self.get_limit_status_v2(resource_family=resource_family)
elif version == 1:
resj = self.get_limit_status_v1(resource_family=resource_family)
else:
raise Exception("Version error: {version}")
#JSON anzeigen
print(self._access_token_mask.sub(r'\g<access_token> "*******************"',
json.dumps(resj, indent=2, ensure_ascii=False)))
#Demontierte Anzeige(remain/Beispiel für das Zurücksetzen)
print("resources:")
if 'resources' in resj:
resources = resj['resources']
for family in resources:
print(f" family: {family}")
endpoints = resources[family]
for endpoint in endpoints:
items = endpoints[endpoint]
print(f" endpoint: {endpoint}")
limit = items['limit']
remaining = items['remaining']
reset = items['reset']
e2d = epoch2datetime(reset)
duration = get_delta(reset)
print(f" limit: {limit}")
print(f" remaining: {remaining}")
print(f" reset: {reset}") #← Eigentlich ein Formular, das dies zurückgibt
print(f" reset(epoch2datetime): {e2d}")
print(f" duration: {duration} sec")
else:
print(" Not Available")
Dies ist das Zeitmanipulationsprogramm und der Anfang der Datei.
getTwitterStatus.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Beispiel für die Erfassung von Twitter-Ratenlimits"""
import os
import sys
import json
from base64 import b64encode
import datetime
import time
import re
import argparse
#!pip install requests
import requests
#!pip install requests_oauthlib
from requests_oauthlib import OAuth1Session
USER_AGENT = "Get Twitter Staus Application/1.0"
TOKEN_ENDPOINT = 'https://api.twitter.com/oauth2/token'
STATUS_ENDPOINT = 'https://api.twitter.com/1.1/application/rate_limit_status.json'
def epoch2datetime(epoch):
"""Epochenzeit(UNIX-Zeit)Terminzeit(localtime)Konvertieren zu"""
return datetime.datetime(*(time.localtime(epoch)[:6]))
def datetime2epoch(d_utc):
"""datetime (UTC)Epochenzeit(UNIX-Zeit)Konvertieren zu"""
#UTC in Ortszeit konvertieren
date_localtime = \
d_utc.replace(tzinfo=datetime.tzinfo.tz.tzutc()).astimezone(datetime.tzinfo.tz.tzlocal())
return int(time.mktime(date_localtime.timetuple()))
def get_delta(target_epoch_time):
"""target_epoch_Gibt die Differenz zwischen der Zeit und der aktuellen Zeit zurück"""
return target_epoch_time - int(round(time.time(), 0))
Da es eine große Sache ist, habe ich versucht, die OAuth-Version und die Ressourcenfamilie mit dem Argument der Befehlszeile anzugeben.
main( )
def main():
"""main()"""
# API_KEY, API_Bestätigung von Umgebungsvariablen wie SEC
apikey = os.getenv('API_KEY', default="")
apisec = os.getenv('API_SEC', default="")
access_token = os.getenv('ACCESS_TOKEN', default="")
access_secret = os.getenv('ACCESS_SECRET', default="")
if apikey == "" or apisec == "": #Wenn die Umgebungsvariable nicht abgerufen werden kann
print("Umgebungsvariablen-API_KEY und API_Bitte stellen Sie SEC ein.", file=sys.stderr)
print("OAuth v1.Umgebungsvariable ACCESS bei Verwendung von 1_Token und Zugang_Stellen Sie auch SECRET ein.",
file=sys.stderr)
sys.exit(255)
#Argumenteinstellung
parser = argparse.ArgumentParser()
parser.add_argument('-a', '--oauthversion', type=int, default=0,
metavar='N', choices=(0, 1, 2),
help=u'OAuth-Versionsspezifikation[1|2]')
parser.add_argument('-f', '--family', type=str, default='search',
metavar='Family',
help=u'API-Familienspezifikation. Durch Kommas für mehrere getrennt')
args = parser.parse_args()
oauthversion = args.oauthversion
family = args.family
#GetTweetStatus-Objekt
gts = GetTweetStatus(apikey, apisec, access_token=access_token, access_secret=access_secret)
# User Auth (OAuth v1.1)Erfassung und Anzeige von Ratenlimits durch
if (oauthversion in (0, 1)) and (access_token != "" and access_secret != ""):
print("<<user auth (OAuth v1)>>")
gts.disp_limit_status(version=1, resource_family=family)
# App Auth (OAuth v2.0)Erfassung und Anzeige von Ratenlimits durch
if oauthversion in (0, 2):
print("<<app auth (OAuth v2)>>")
gts.disp_limit_status(version=2, resource_family=family)
if __name__ == "__main__":
main()
getTwitterStatus.py
[^ 2]: Ich habe zum ersten Mal versucht, Gist zu verwenden. Ich mache mir Sorgen, ob die Verwendung korrekt ist.
$ python3 getTwitterStatus.py
<<user auth (OAuth v1)>>
{
"rate_limit_context": {
"access_token": "*******************"
},
"resources": {
"search": {
"/search/tweets": {
"limit": 180,
"remaining": 180,
"reset": 1591016735
}
}
}
}
resources:
family: search
endpoint: /search/tweets
limit: 180
remaining: 180
reset: 1591016735
reset(epoch2datetime): 2020-06-01 22:05:35
duration: 899 sec
<<app auth (OAuth v2)>>
{
"rate_limit_context": {
"application": "dummykey"
},
"resources": {
"search": {
"/search/tweets": {
"limit": 450,
"remaining": 450,
"reset": 1591016736
}
}
}
}
resources:
family: search
endpoint: /search/tweets
limit: 450
remaining: 450
reset: 1591016736
reset(epoch2datetime): 2020-06-01 22:05:36
duration: 900 sec
$
Es gibt eine Begrenzung für die Häufigkeit, mit der Sie es gleichzeitig erhalten können, unabhängig von der Begrenzung.
200 ($ count \ leq200 search / tweets
.
Es gibt verschiedene andere Einschränkungen, aber im Fall von "Suche / Tweets" wird das Element "next_results" in "search_metadata" aufgenommen, damit es kontinuierlich abgerufen werden kann.
{
"statuses": [
...
],
"search_metadata": {
"completed_in": 0.047,
"max_id": 1125490788736032770,
"max_id_str": "1125490788736032770",
"next_results": "?max_id=1124690280777699327&q=from%3Atwitterdev&count=2&include_entities=1&result_type=mixed",
"query": "from%3Atwitterdev",
"refresh_url": "?since_id=1125490788736032770&q=from%3Atwitterdev&result_type=mixed&include_entities=1",
"count": 2,
"since_id": 0,
"since_id_str": "0"
}
}
Es gibt "next_results" in "search_metadata". Wenn Sie dies als neuen Parameter anfordern, können Sie auch den Rest der Suchergebnisse abrufen (in den in count angegebenen Einheiten).
Solange Sie das Zeitlimit nicht erreichen, können Sie sich darauf beziehen und wiederholen, um die Ergebnisse kontinuierlich zu erhalten. Das heißt, Sie können $ count $ (bis zu 100) $ × limit $ (180 für Benutzerauthentifizierung) $ = 18.000 Tweet $ in Rate Limit erhalten.
Im Fall des obigen Beispiels ist $ count = 2 $. Wenn Sie also so weitermachen, wie es ist, können Sie $ count (2) Tweets / Zeit x Limit (180) mal / 15 Minuten = 360 Tweets / 15 Minuten $ erhalten, und Sie sind begrenzt. Erreichen Sie (natürlich, wenn Sie Krebs anfordern).
Wenn alle Suchergebnisse erhalten wurden, verschwindet "next_results" aus "search_metadata".
Wenn Sie es erneut anfordern, wird "next_results" manchmal wiederhergestellt, sodass Sie möglicherweise eine Weile warten und es erneut versuchen möchten.
Im Fall von "statuses / user_timeline" usw. ist "* _metadata" nicht enthalten. Verwenden Sie daher die Spezifikation von "max_id" und generieren Sie selbst etwas, das "next_results" der Suche entspricht. wird gebraucht. (Eigentlich habe ich es nur für die Suche verwendet, daher bin ich mir nicht sicher, aber ich denke, es ist nicht so weit weg.)
Bei der Suche werden die letzten 7 Tage als Ziel ausgewählt, aber da "user_timeline" die letzten 24 Stunden sind, denke ich, dass der Zweck in erster Linie anders ist ...
Recommended Posts