Pythons Anforderungsbibliothek (Handbuch)

Pythons Anforderungsbibliothek (Handbuch)

Dierequests-Bibliothek ist der De-facto-Standard für HTTP-Anforderungen in Python. Es abstrahiert die Komplexität der Anforderung hinter einer schönen, einfachen API, sodass Sie sich auf die Interaktion mit Diensten und den Verbrauch von Daten in Ihrer Anwendung konzentrieren können.

In diesem Artikel werden einige der nützlichsten Funktionen vonrequests vorgestellt sowie Informationen zum Anpassen und Optimieren dieser Funktionen für verschiedene Situationen, auf die Sie möglicherweise stoßen. Außerdem erfahren Sie, wie Sierequests effizient verwenden und verhindern, dass Anforderungen an externe Dienste Ihre Anwendung verlangsamen.

In diesem Tutorial erfahren Sie, wie Sie:

  • Make requests mit den gängigsten HTTP-Methoden

  • Customizeind die Header und Daten Ihrer Anforderungen unter Verwendung der Abfragezeichenfolge und des Nachrichtentexts

  • Inspect Daten aus Ihren Anfragen und Antworten

  • Stellen Sieauthenticated Anfragen

  • Configure Ihre Anforderungen, um zu verhindern, dass Ihre Anwendung gesichert oder verlangsamt wird

Obwohl ich versucht habe, so viele Informationen wie möglich anzugeben, um die in diesem Artikel enthaltenen Funktionen und Beispiele zu verstehen, gehe ich von einemverybasic general knowledge of HTTP aus. Trotzdem können Sie vielleicht trotzdem gut mitmachen.

Nachdem dies nicht mehr möglich ist, wollen wir uns ansehen, wie Sierequests in Ihrer Anwendung verwenden können!

Erste Schritte mitrequests

Beginnen wir mit der Installation derrequests-Bibliothek. Führen Sie dazu den folgenden Befehl aus:

$ pip install requests

Wenn SiePipenv zum Verwalten von Python-Paketen bevorzugen, können Sie Folgendes ausführen:

$ pipenv install requests

Sobaldrequests installiert ist, können Sie es in Ihrer Anwendung verwenden. Das Importieren vonrequests sieht folgendermaßen aus:

import requests

Jetzt, da Sie alle eingerichtet sind, ist es Zeit, Ihre Reise durchrequests zu beginnen. Ihr erstes Ziel wird sein, zu lernen, wie Sie eineGET-Anforderung stellen.

Die GET-Anfrage

HTTP methods wieGET undPOST bestimmen, welche Aktion Sie ausführen möchten, wenn Sie eine HTTP-Anforderung stellen. NebenGET undPOST gibt es noch einige andere gängige Methoden, die Sie später in diesem Lernprogramm verwenden werden.

Eine der häufigsten HTTP-Methoden istGET. Die MethodeGET gibt an, dass Sie versuchen, Daten von einer bestimmten Ressource abzurufen oder abzurufen. Rufen Sierequests.get() auf, um eineGET-Anforderung zu stellen.

Um dies zu testen, können Sie eineGET-Anforderung an GitHubsRoot REST API stellen, indem Sieget() mit der folgenden URL aufrufen:

>>>

>>> requests.get('https://api.github.com')

Herzliche Glückwünsche! Sie haben Ihre erste Anfrage gestellt. Lassen Sie uns etwas tiefer in die Antwort auf diese Anfrage eintauchen.

Die Antwort

AResponse ist ein leistungsfähiges Objekt zum Überprüfen der Ergebnisse der Anforderung. Lassen Sie uns dieselbe Anforderung erneut stellen, aber speichern Sie diesmal den Rückgabewert in einer Variablen, damit Sie die Attribute und Verhaltensweisen genauer betrachten können:

>>>

>>> response = requests.get('https://api.github.com')

In diesem Beispiel haben Sie den Rückgabewert vonget(), einer Instanz vonResponse, erfasst und in einer Variablen namensresponse gespeichert. Sie können jetztresponse verwenden, um viele Informationen zu den Ergebnissen IhrerGET-Anforderung anzuzeigen.

Statuscodes

Die erste Information, die Sie ausResponse sammeln können, ist der Statuscode. Ein Statuscode informiert Sie über den Status der Anfrage.

Beispielsweise bedeutet der Status eines200 OK, dass Ihre Anforderung erfolgreich war, während der Status eines404 NOT FOUNDbedeutet, dass die gesuchte Ressource nicht gefunden wurde. Es gibt auchmany other possible status codes, um Ihnen spezifische Einblicke in das zu geben, was mit Ihrer Anfrage passiert ist.

Durch Zugriff auf.status_code können Sie den vom Server zurückgegebenen Statuscode anzeigen:

>>>

>>> response.status_code
200

.status_code hat ein200 zurückgegeben, was bedeutet, dass Ihre Anfrage erfolgreich war und der Server mit den von Ihnen angeforderten Daten geantwortet hat.

Manchmal möchten Sie diese Informationen möglicherweise verwenden, um Entscheidungen in Ihrem Code zu treffen:

if response.status_code == 200:
    print('Success!')
elif response.status_code == 404:
    print('Not Found.')

Wenn der Server mit dieser Logik den Statuscode200zurückgibt, gibt Ihr ProgrammSuccess! aus. Wenn das Ergebnis404 ist, druckt Ihr ProgrammNot Found.

requests geht noch einen Schritt weiter, um diesen Prozess für Sie zu vereinfachen. Wenn Sie eineResponse-Instanz in einem bedingten Ausdruck verwenden, wirdTrue ausgewertet, wenn der Statuscode zwischen200 und400 liegt, andernfallsFalse.

Daher können Sie das letzte Beispiel vereinfachen, indem Sie die Anweisungifneu schreiben:

if response:
    print('Success!')
else:
    print('An error has occurred.')

Technical Detail: DiesesTruth Value Test wird ermöglicht, weil__bool__() is an overloaded method aufResponse liegt.

Dies bedeutet, dass das Standardverhalten vonResponse neu definiert wurde, um den Statuscode bei der Ermittlung des Wahrheitswerts des Objekts zu berücksichtigen.

Beachten Sie, dass diese Methodenot ist und überprüft, ob der Statuscode200 entspricht. Der Grund dafür ist, dass andere Statuscodes im Bereich von200 bis400, wie204 NO CONTENT und304 NOT MODIFIED, ebenfalls als erfolgreich angesehen werden, da sie einige funktionsfähig sind Antwort.

Zum Beispiel zeigt204 an, dass die Antwort erfolgreich war, aber es gibt keinen Inhalt, der im Nachrichtentext zurückgegeben werden kann.

Stellen Sie daher sicher, dass Sie diese praktische Abkürzung nur verwenden, wenn Sie wissen möchten, ob die Anforderung im Allgemeinen erfolgreich war, und behandeln Sie die Antwort gegebenenfalls entsprechend dem Statuscode entsprechend.

Angenommen, Sie möchten den Statuscode der Antwort in einerif-Anweisung nicht überprüfen. Stattdessen möchten Sie eine Ausnahme auslösen, wenn die Anforderung nicht erfolgreich war. Sie können dies mit.raise_for_status() tun:

import requests
from requests.exceptions import HTTPError

for url in ['https://api.github.com', 'https://api.github.com/invalid']:
    try:
        response = requests.get(url)

        # If the response was successful, no Exception will be raised
        response.raise_for_status()
    except HTTPError as http_err:
        print(f'HTTP error occurred: {http_err}')  # Python 3.6
    except Exception as err:
        print(f'Other error occurred: {err}')  # Python 3.6
    else:
        print('Success!')

Wenn Sie.raise_for_status() aufrufen, wird für bestimmte Statuscodes einHTTPError ausgelöst. Wenn der Statuscode eine erfolgreiche Anforderung anzeigt, wird das Programm fortgesetzt, ohne dass diese Ausnahme ausgelöst wird.

Further Reading: Wenn Sie mitf-stringsvon Python 3.6 nicht vertraut sind, empfehlen wir Ihnen, diese zu nutzen, da sie eine großartige Möglichkeit sind, Ihre formatierten Zeichenfolgen zu vereinfachen.

Jetzt wissen Sie viel darüber, wie Sie mit dem Statuscode der Antwort umgehen müssen, die Sie vom Server erhalten haben. Wenn Sie jedoch eineGET-Anforderung stellen, ist Ihnen selten nur der Statuscode der Antwort wichtig. Normalerweise möchten Sie mehr sehen. Als Nächstes sehen Sie, wie Sie die tatsächlichen Daten anzeigen, die der Server im Hauptteil der Antwort zurückgesendet hat.

Inhalt

Die Antwort einerGET-Anforderung enthält häufig einige wertvolle Informationen, die als Nutzdaten bezeichnet werden, im Nachrichtentext. Mit den Attributen und Methoden vonResponse können Sie die Nutzlast in verschiedenen Formaten anzeigen.

Um den Inhalt der Antwort inbytes anzuzeigen, verwenden Sie.content:

>>>

>>> response = requests.get('https://api.github.com')
>>> response.content
b'{"current_user_url":"https://api.github.com/user","current_user_authorizations_html_url":"https://github.com/settings/connections/applications{/client_id}","authorizations_url":"https://api.github.com/authorizations","code_search_url":"https://api.github.com/search/code?q={query}{&page,per_page,sort,order}","commit_search_url":"https://api.github.com/search/commits?q={query}{&page,per_page,sort,order}","emails_url":"https://api.github.com/user/emails","emojis_url":"https://api.github.com/emojis","events_url":"https://api.github.com/events","feeds_url":"https://api.github.com/feeds","followers_url":"https://api.github.com/user/followers","following_url":"https://api.github.com/user/following{/target}","gists_url":"https://api.github.com/gists{/gist_id}","hub_url":"https://api.github.com/hub","issue_search_url":"https://api.github.com/search/issues?q={query}{&page,per_page,sort,order}","issues_url":"https://api.github.com/issues","keys_url":"https://api.github.com/user/keys","notifications_url":"https://api.github.com/notifications","organization_repositories_url":"https://api.github.com/orgs/{org}/repos{?type,page,per_page,sort}","organization_url":"https://api.github.com/orgs/{org}","public_gists_url":"https://api.github.com/gists/public","rate_limit_url":"https://api.github.com/rate_limit","repository_url":"https://api.github.com/repos/{owner}/{repo}","repository_search_url":"https://api.github.com/search/repositories?q={query}{&page,per_page,sort,order}","current_user_repositories_url":"https://api.github.com/user/repos{?type,page,per_page,sort}","starred_url":"https://api.github.com/user/starred{/owner}{/repo}","starred_gists_url":"https://api.github.com/gists/starred","team_url":"https://api.github.com/teams","user_url":"https://api.github.com/users/{user}","user_organizations_url":"https://api.github.com/user/orgs","user_repositories_url":"https://api.github.com/users/{user}/repos{?type,page,per_page,sort}","user_search_url":"https://api.github.com/search/users?q={query}{&page,per_page,sort,order}"}'

Während Sie mit.content auf die Rohbytes der Antwortnutzdaten zugreifen können, möchten Sie diese häufig mit einer Zeichencodierung wieUTF-8 instring konvertieren. response erledigt das für Sie, wenn Sie auf.text zugreifen:

>>>

>>> response.text
'{"current_user_url":"https://api.github.com/user","current_user_authorizations_html_url":"https://github.com/settings/connections/applications{/client_id}","authorizations_url":"https://api.github.com/authorizations","code_search_url":"https://api.github.com/search/code?q={query}{&page,per_page,sort,order}","commit_search_url":"https://api.github.com/search/commits?q={query}{&page,per_page,sort,order}","emails_url":"https://api.github.com/user/emails","emojis_url":"https://api.github.com/emojis","events_url":"https://api.github.com/events","feeds_url":"https://api.github.com/feeds","followers_url":"https://api.github.com/user/followers","following_url":"https://api.github.com/user/following{/target}","gists_url":"https://api.github.com/gists{/gist_id}","hub_url":"https://api.github.com/hub","issue_search_url":"https://api.github.com/search/issues?q={query}{&page,per_page,sort,order}","issues_url":"https://api.github.com/issues","keys_url":"https://api.github.com/user/keys","notifications_url":"https://api.github.com/notifications","organization_repositories_url":"https://api.github.com/orgs/{org}/repos{?type,page,per_page,sort}","organization_url":"https://api.github.com/orgs/{org}","public_gists_url":"https://api.github.com/gists/public","rate_limit_url":"https://api.github.com/rate_limit","repository_url":"https://api.github.com/repos/{owner}/{repo}","repository_search_url":"https://api.github.com/search/repositories?q={query}{&page,per_page,sort,order}","current_user_repositories_url":"https://api.github.com/user/repos{?type,page,per_page,sort}","starred_url":"https://api.github.com/user/starred{/owner}{/repo}","starred_gists_url":"https://api.github.com/gists/starred","team_url":"https://api.github.com/teams","user_url":"https://api.github.com/users/{user}","user_organizations_url":"https://api.github.com/user/orgs","user_repositories_url":"https://api.github.com/users/{user}/repos{?type,page,per_page,sort}","user_search_url":"https://api.github.com/search/users?q={query}{&page,per_page,sort,order}"}'

Da für die Dekodierung vonbytes zustr ein Kodierungsschema erforderlich ist, versuchtrequests, dieencoding basierend auf denheaders der Antwort zu erraten, wenn Sie dies nicht angeben ein. Sie können eine explizite Codierung bereitstellen, indem Sie.encoding festlegen, bevor Sie auf.text zugreifen:

>>>

>>> response.encoding = 'utf-8' # Optional: requests infers this internally
>>> response.text
'{"current_user_url":"https://api.github.com/user","current_user_authorizations_html_url":"https://github.com/settings/connections/applications{/client_id}","authorizations_url":"https://api.github.com/authorizations","code_search_url":"https://api.github.com/search/code?q={query}{&page,per_page,sort,order}","commit_search_url":"https://api.github.com/search/commits?q={query}{&page,per_page,sort,order}","emails_url":"https://api.github.com/user/emails","emojis_url":"https://api.github.com/emojis","events_url":"https://api.github.com/events","feeds_url":"https://api.github.com/feeds","followers_url":"https://api.github.com/user/followers","following_url":"https://api.github.com/user/following{/target}","gists_url":"https://api.github.com/gists{/gist_id}","hub_url":"https://api.github.com/hub","issue_search_url":"https://api.github.com/search/issues?q={query}{&page,per_page,sort,order}","issues_url":"https://api.github.com/issues","keys_url":"https://api.github.com/user/keys","notifications_url":"https://api.github.com/notifications","organization_repositories_url":"https://api.github.com/orgs/{org}/repos{?type,page,per_page,sort}","organization_url":"https://api.github.com/orgs/{org}","public_gists_url":"https://api.github.com/gists/public","rate_limit_url":"https://api.github.com/rate_limit","repository_url":"https://api.github.com/repos/{owner}/{repo}","repository_search_url":"https://api.github.com/search/repositories?q={query}{&page,per_page,sort,order}","current_user_repositories_url":"https://api.github.com/user/repos{?type,page,per_page,sort}","starred_url":"https://api.github.com/user/starred{/owner}{/repo}","starred_gists_url":"https://api.github.com/gists/starred","team_url":"https://api.github.com/teams","user_url":"https://api.github.com/users/{user}","user_organizations_url":"https://api.github.com/user/orgs","user_repositories_url":"https://api.github.com/users/{user}/repos{?type,page,per_page,sort}","user_search_url":"https://api.github.com/search/users?q={query}{&page,per_page,sort,order}"}'

Wenn Sie sich die Antwort ansehen, werden Sie feststellen, dass es sich tatsächlich um serialisierten JSON-Inhalt handelt. Um ein Wörterbuch zu erhalten, können Sie diestr, die Sie aus.text abgerufen haben, mitjson.loads() deserialisieren. Eine einfachere Möglichkeit, diese Aufgabe auszuführen, ist die Verwendung von.json():

>>>

>>> response.json()
{'current_user_url': 'https://api.github.com/user', 'current_user_authorizations_html_url': 'https://github.com/settings/connections/applications{/client_id}', 'authorizations_url': 'https://api.github.com/authorizations', 'code_search_url': 'https://api.github.com/search/code?q={query}{&page,per_page,sort,order}', 'commit_search_url': 'https://api.github.com/search/commits?q={query}{&page,per_page,sort,order}', 'emails_url': 'https://api.github.com/user/emails', 'emojis_url': 'https://api.github.com/emojis', 'events_url': 'https://api.github.com/events', 'feeds_url': 'https://api.github.com/feeds', 'followers_url': 'https://api.github.com/user/followers', 'following_url': 'https://api.github.com/user/following{/target}', 'gists_url': 'https://api.github.com/gists{/gist_id}', 'hub_url': 'https://api.github.com/hub', 'issue_search_url': 'https://api.github.com/search/issues?q={query}{&page,per_page,sort,order}', 'issues_url': 'https://api.github.com/issues', 'keys_url': 'https://api.github.com/user/keys', 'notifications_url': 'https://api.github.com/notifications', 'organization_repositories_url': 'https://api.github.com/orgs/{org}/repos{?type,page,per_page,sort}', 'organization_url': 'https://api.github.com/orgs/{org}', 'public_gists_url': 'https://api.github.com/gists/public', 'rate_limit_url': 'https://api.github.com/rate_limit', 'repository_url': 'https://api.github.com/repos/{owner}/{repo}', 'repository_search_url': 'https://api.github.com/search/repositories?q={query}{&page,per_page,sort,order}', 'current_user_repositories_url': 'https://api.github.com/user/repos{?type,page,per_page,sort}', 'starred_url': 'https://api.github.com/user/starred{/owner}{/repo}', 'starred_gists_url': 'https://api.github.com/gists/starred', 'team_url': 'https://api.github.com/teams', 'user_url': 'https://api.github.com/users/{user}', 'user_organizations_url': 'https://api.github.com/user/orgs', 'user_repositories_url': 'https://api.github.com/users/{user}/repos{?type,page,per_page,sort}', 'user_search_url': 'https://api.github.com/search/users?q={query}{&page,per_page,sort,order}'}

type des Rückgabewerts von.json() ist ein Wörterbuch, sodass Sie per Schlüssel auf Werte im Objekt zugreifen können.

Mit Statuscodes und Nachrichtentexten können Sie viel anfangen. Wenn Sie jedoch weitere Informationen benötigen, z. B. Metadaten zur Antwort selbst, müssen Sie sich die Header der Antwort ansehen.

Überschriften

Die Antwortheader können nützliche Informationen enthalten, z. B. den Inhaltstyp der Antwortnutzlast und ein Zeitlimit für die Zwischenspeicherung der Antwort. Um diese Header anzuzeigen, greifen Sie auf.headers zu:

>>>

>>> response.headers
{'Server': 'GitHub.com', 'Date': 'Mon, 10 Dec 2018 17:49:54 GMT', 'Content-Type': 'application/json; charset=utf-8', 'Transfer-Encoding': 'chunked', 'Status': '200 OK', 'X-RateLimit-Limit': '60', 'X-RateLimit-Remaining': '59', 'X-RateLimit-Reset': '1544467794', 'Cache-Control': 'public, max-age=60, s-maxage=60', 'Vary': 'Accept', 'ETag': 'W/"7dc470913f1fe9bb6c7355b50a0737bc"', 'X-GitHub-Media-Type': 'github.v3; format=json', 'Access-Control-Expose-Headers': 'ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type', 'Access-Control-Allow-Origin': '*', 'Strict-Transport-Security': 'max-age=31536000; includeSubdomains; preload', 'X-Frame-Options': 'deny', 'X-Content-Type-Options': 'nosniff', 'X-XSS-Protection': '1; mode=block', 'Referrer-Policy': 'origin-when-cross-origin, strict-origin-when-cross-origin', 'Content-Security-Policy': "default-src 'none'", 'Content-Encoding': 'gzip', 'X-GitHub-Request-Id': 'E439:4581:CF2351:1CA3E06:5C0EA741'}

.headers gibt ein wörterbuchähnliches Objekt zurück, mit dem Sie per Schlüssel auf Header-Werte zugreifen können. Um beispielsweise den Inhaltstyp der Antwortnutzlast anzuzeigen, können Sie aufContent-Type zugreifen:

>>>

>>> response.headers['Content-Type']
'application/json; charset=utf-8'

Dieses wörterbuchartige Header-Objekt hat jedoch etwas Besonderes. Die HTTP-Spezifikation definiert Header so, dass die Groß- und Kleinschreibung nicht berücksichtigt wird. Dies bedeutet, dass wir auf diese Header zugreifen können, ohne uns um ihre Großschreibung kümmern zu müssen:

>>>

>>> response.headers['content-type']
'application/json; charset=utf-8'

Unabhängig davon, ob Sie den Schlüssel'content-type' oder'Content-Type' verwenden, erhalten Sie den gleichen Wert.

Jetzt haben Sie die Grundlagen zuResponse gelernt. Sie haben die nützlichsten Attribute und Methoden in Aktion gesehen. Machen wir einen Schritt zurück und sehen, wie sich Ihre Antworten ändern, wenn Sie die Anforderungen vonGETanpassen.

Parameter für Abfragezeichenfolgen

Eine übliche Methode zum Anpassen der Anforderung vonGETbesteht darin, Werte über die Parameter vonquery stringin der URL zu übergeben. Dazu übergeben Sie mitget() Daten anparams. Sie können beispielsweise dieSearch-API von GitHub verwenden, um nach derrequests-Bibliothek zu suchen:

import requests

# Search GitHub's repositories for requests
response = requests.get(
    'https://api.github.com/search/repositories',
    params={'q': 'requests+language:python'},
)

# Inspect some attributes of the `requests` repository
json_response = response.json()
repository = json_response['items'][0]
print(f'Repository name: {repository["name"]}')  # Python 3.6+
print(f'Repository description: {repository["description"]}')  # Python 3.6+

Durch Übergeben des Wörterbuchs{'q': 'requests+language:python'} an den Parameterparams von.get() können Sie die Ergebnisse ändern, die von der Such-API zurückgegeben werden.

Sie könnenparams anget() in Form eines Wörterbuchs übergeben, wie Sie es gerade getan haben, oder als Liste von Tupeln:

>>>

>>> requests.get(
...     'https://api.github.com/search/repositories',
...     params=[('q', 'requests+language:python')],
... )

Sie können die Werte sogar alsbytes übergeben:

>>>

>>> requests.get(
...     'https://api.github.com/search/repositories',
...     params=b'q=requests+language:python',
... )

Abfragezeichenfolgen sind nützlich, um die Anforderungen vonGETzu parametrisieren. Sie können Ihre Anforderungen auch anpassen, indem Sie die von Ihnen gesendeten Header hinzufügen oder ändern.

Header anfordern

Um Header anzupassen, übergeben Sie ein Wörterbuch mit HTTP-Headern anget() mit dem Parameterheaders. Sie können beispielsweise Ihre vorherige Suchanforderung ändern, um übereinstimmende Suchbegriffe in den Ergebnissen hervorzuheben, indem Sie den Medientyptext-matchin der KopfzeileAcceptangeben:

import requests

response = requests.get(
    'https://api.github.com/search/repositories',
    params={'q': 'requests+language:python'},
    headers={'Accept': 'application/vnd.github.v3.text-match+json'},
)

# View the new `text-matches` array which provides information
# about your search term within the results
json_response = response.json()
repository = json_response['items'][0]
print(f'Text matches: {repository["text_matches"]}')

Der HeaderAcceptteilt dem Server mit, welche Inhaltstypen Ihre Anwendung verarbeiten kann. In diesem Fall verwenden Sie, da Sie erwarten, dass die übereinstimmenden Suchbegriffe hervorgehoben werden, den Headerwertapplication/vnd.github.v3.text-match+json, einen proprietären GitHubAccept-Header, bei dem der Inhalt ein spezielles JSON-Format hat.

Bevor Sie weitere Möglichkeiten zum Anpassen von Anforderungen kennenlernen, erweitern wir den Horizont, indem wir andere HTTP-Methoden untersuchen.

Andere HTTP-Methoden

NebenGET umfassen andere beliebte HTTP-MethodenPOST,PUT,DELETE,HEAD,PATCH undOPTIONS. requests bietet für jede dieser HTTP-Methoden eine Methode mit einer ähnlichen Signatur wieget():

>>>

>>> requests.post('https://httpbin.org/post', data={'key':'value'})
>>> requests.put('https://httpbin.org/put', data={'key':'value'})
>>> requests.delete('https://httpbin.org/delete')
>>> requests.head('https://httpbin.org/get')
>>> requests.patch('https://httpbin.org/patch', data={'key':'value'})
>>> requests.options('https://httpbin.org/get')

Jeder Funktionsaufruf sendet eine Anforderung an den Diensthttpbinunter Verwendung der entsprechenden HTTP-Methode. Für jede Methode können Sie ihre Antworten auf dieselbe Weise wie zuvor überprüfen:

>>>

>>> response = requests.head('https://httpbin.org/get')
>>> response.headers['Content-Type']
'application/json'

>>> response = requests.delete('https://httpbin.org/delete')
>>> json_response = response.json()
>>> json_response['args']
{}

Header, Antwortkörper, Statuscodes und mehr werden für jede Methode inResponse zurückgegeben. Als Nächstes sehen Sie sich die MethodenPOST,PUT undPATCHgenauer an und erfahren, wie sie sich von den anderen Anforderungstypen unterscheiden.

Der Nachrichtentext

Gemäß der HTTP-Spezifikation leitenPOST,PUT und die weniger häufigenPATCH-Anforderungen ihre Daten über den Nachrichtentext und nicht über Parameter in der Abfragezeichenfolge weiter. Mitrequests übergeben Sie die Nutzdaten an dendata-Parameter der entsprechenden Funktion.

data verwendet ein Wörterbuch, eine Liste von Tupeln, Bytes oder ein dateiähnliches Objekt. Sie möchten die Daten, die Sie im Hauptteil Ihrer Anfrage senden, an die spezifischen Anforderungen des Dienstes anpassen, mit dem Sie interagieren.

Wenn der Inhaltstyp Ihrer Anfrage beispielsweiseapplication/x-www-form-urlencoded ist, können Sie die Formulardaten als Wörterbuch senden:

>>>

>>> requests.post('https://httpbin.org/post', data={'key':'value'})

Sie können dieselben Daten auch als Liste von Tupeln senden:

>>>

>>> requests.post('https://httpbin.org/post', data=[('key', 'value')])

Wenn Sie jedoch JSON-Daten senden müssen, können Sie den Parameterjsonverwenden. Wenn Sie JSON-Daten überjson übergeben, serialisiertrequests Ihre Daten und fügt den richtigenContent-Type-Header für Sie hinzu.

httpbin.org ist eine großartige Ressource, die vom Autor vonrequests,Kenneth Reitz erstellt wurde. Es ist ein Dienst, der Testanforderungen akzeptiert und mit Daten zu den Anforderungen antwortet. Sie können es beispielsweise verwenden, um die Anforderung eines einfachenPOSTzu überprüfen:

>>>

>>> response = requests.post('https://httpbin.org/post', json={'key':'value'})
>>> json_response = response.json()
>>> json_response['data']
'{"key": "value"}'
>>> json_response['headers']['Content-Type']
'application/json'

Sie können der Antwort entnehmen, dass der Server Ihre Anforderungsdaten und Header beim Senden empfangen hat. requests stellt Ihnen diese Informationen auch in Form vonPreparedRequest zur Verfügung.

Überprüfen Sie Ihre Anfrage

Wenn Sie eine Anfrage stellen, bereitet die Bibliothek vonrequestsdie Anfrage vor, bevor sie tatsächlich an den Zielserver gesendet wird. Die Anforderungsvorbereitung umfasst Dinge wie das Überprüfen von Headern und das Serialisieren von JSON-Inhalten.

Sie können diePreparedRequest anzeigen, indem Sie auf.request zugreifen:

>>>

>>> response = requests.post('https://httpbin.org/post', json={'key':'value'})
>>> response.request.headers['Content-Type']
'application/json'
>>> response.request.url
'https://httpbin.org/post'
>>> response.request.body
b'{"key": "value"}'

Durch Überprüfen derPreparedRequest erhalten Sie Zugriff auf alle Arten von Informationen über die angeforderte Anforderung, z. B. Nutzdaten, URL, Header, Authentifizierung und mehr.

Bisher haben Sie viele verschiedene Arten von Anfragen gestellt, aber alle hatten eines gemeinsam: Es handelt sich um nicht authentifizierte Anfragen an öffentliche APIs. Bei vielen Diensten, auf die Sie möglicherweise stoßen, möchten Sie, dass Sie sich auf irgendeine Weise authentifizieren.

Authentifizierung

Die Authentifizierung hilft einem Dienst zu verstehen, wer Sie sind. In der Regel geben Sie Ihre Anmeldeinformationen an einen Server weiter, indem Sie Daten über den HeaderAuthorizationoder einen vom Dienst definierten benutzerdefinierten Header übergeben. Alle Anforderungsfunktionen, die Sie bisher gesehen haben, bieten einen Parameter namensauth, mit dem Sie Ihre Anmeldeinformationen übergeben können.

Ein Beispiel für eine API, die eine Authentifizierung erfordert, ist dieAuthenticated User-API von GitHub. Dieser Endpunkt enthält Informationen zum Profil des authentifizierten Benutzers. Um eine Anfrage an die API für authentifizierte Benutzer zu stellen, können Sie Ihren GitHub-Benutzernamen und Ihr Kennwort in einem Tupel anget() übergeben:

>>>

>>> from getpass import getpass
>>> requests.get('https://api.github.com/user', auth=('username', getpass()))

Die Anforderung war erfolgreich, wenn die Anmeldeinformationen, die Sie im Tupel anauth übergeben haben, gültig sind. Wenn Sie versuchen, diese Anforderung ohne Anmeldeinformationen zu stellen, wird der Statuscode401 Unauthorized lauten:

>>>

>>> requests.get('https://api.github.com/user')

Wenn Sie Ihren Benutzernamen und Ihr Kennwort in einem Tupel an den Parameterauth übergeben, wendetrequests die Anmeldeinformationen mithilfe derBasic access authentication scheme von HTTP unter der Haube an.

Daher können Sie dieselbe Anforderung stellen, indem Sie explizite Anmeldeinformationen für die Standardauthentifizierung mitHTTPBasicAuth übergeben:

>>>

>>> from requests.auth import HTTPBasicAuth
>>> from getpass import getpass
>>> requests.get(
...     'https://api.github.com/user',
...     auth=HTTPBasicAuth('username', getpass())
... )

Obwohl Sie für die Standardauthentifizierung nicht explizit sein müssen, möchten Sie sich möglicherweise mit einer anderen Methode authentifizieren. requests bietet standardmäßige andere Authentifizierungsmethoden wieHTTPDigestAuth undHTTPProxyAuth.

Sie können sogar Ihren eigenen Authentifizierungsmechanismus bereitstellen. Dazu müssen Sie zunächst eine Unterklasse vonAuthBase erstellen. Dann implementieren Sie__call__():

import requests
from requests.auth import AuthBase

class TokenAuth(AuthBase):
    """Implements a custom authentication scheme."""

    def __init__(self, token):
        self.token = token

    def __call__(self, r):
        """Attach an API token to a custom auth header."""
        r.headers['X-TokenAuth'] = f'{self.token}'  # Python 3.6+
        return r


requests.get('https://httpbin.org/get', auth=TokenAuth('12345abcde-token'))

Hier empfängt der Mechanismus Ihres benutzerdefiniertenTokenAuthein Token und nimmt dieses Token dann in den Header vonX-TokenAuthIhrer Anfrage auf.

Schlechte Authentifizierungsmechanismen können zu Sicherheitslücken führen. Wenn für einen Dienst aus irgendeinem Grund kein benutzerdefinierter Authentifizierungsmechanismus erforderlich ist, sollten Sie immer ein bewährtes Authentifizierungsschema wie Basic oder OAuth verwenden.

Wenn Sie über Sicherheit nachdenken, sollten Sie den Umgang mit SSL-Zertifikaten mitrequests in Betracht ziehen.

Überprüfung des SSL-Zertifikats

Jedes Mal, wenn die Daten, die Sie senden oder empfangen möchten, vertraulich sind, ist die Sicherheit wichtig. Die Art und Weise, wie Sie mit sicheren Sites über HTTP kommunizieren, besteht darin, eine verschlüsselte Verbindung mit SSL herzustellen. Daher ist die Überprüfung des SSL-Zertifikats des Zielservers von entscheidender Bedeutung.

Die gute Nachricht ist, dassrequests dies standardmäßig für Sie erledigt. Es gibt jedoch einige Fälle, in denen Sie dieses Verhalten möglicherweise ändern möchten.

Wenn Sie die Überprüfung des SSL-Zertifikats deaktivieren möchten, übergeben SieFalse an den Parameterverify der Anforderungsfunktion:

>>>

>>> requests.get('https://api.github.com', verify=False)
InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
  InsecureRequestWarning)

requests warnt Sie sogar, wenn Sie eine unsichere Anfrage stellen, um Ihre Daten zu schützen!

Note:requests uses a package called certifi zur Bereitstellung von Zertifizierungsstellen. Dadurch erfahrenrequests, welchen Behörden sie vertrauen können. Daher sollten Siecertifi regelmäßig aktualisieren, um Ihre Verbindungen so sicher wie möglich zu halten.

Performance

Bei der Verwendung vonrequests, insbesondere in einer Produktionsanwendungsumgebung, ist es wichtig, die Auswirkungen auf die Leistung zu berücksichtigen. Funktionen wie Timeout-Kontrolle, Sitzungen und Wiederholungslimits können Ihnen dabei helfen, dass Ihre Anwendung reibungslos läuft.

Timeouts

Wenn Sie eine Inline-Anfrage an einen externen Dienst stellen, muss Ihr System auf die Antwort warten, bevor Sie fortfahren. Wenn Ihre Anwendung zu lange auf diese Antwort wartet, können Anforderungen an Ihren Dienst gesichert werden, Ihre Benutzererfahrung kann darunter leiden oder Ihre Hintergrundjobs können hängen bleiben.

Standardmäßig wartetrequests unbegrenzt auf die Antwort. Daher sollten Sie fast immer eine Zeitüberschreitungsdauer angeben, um zu verhindern, dass diese Ereignisse auftreten. Verwenden Sie den Parametertimeout, um das Zeitlimit der Anforderung festzulegen. timeout kann eine Ganzzahl oder ein Gleitkommawert sein, der die Anzahl der Sekunden darstellt, die auf eine Antwort gewartet werden muss, bevor eine Zeitüberschreitung auftritt:

>>>

>>> requests.get('https://api.github.com', timeout=1)

>>> requests.get('https://api.github.com', timeout=3.05)

Bei der ersten Anforderung tritt nach 1 Sekunde eine Zeitüberschreitung für die Anforderung auf. Bei der zweiten Anforderung tritt nach 3,05 Sekunden eine Zeitüberschreitung für die Anforderung auf.

You can also pass a tuple bistimeout, wobei das erste Element ein Verbindungszeitlimit ist (die Zeit, die es dem Client ermöglicht, eine Verbindung zum Server herzustellen) und das zweite ein Lesezeitlimit ist (die Zeit, auf die es wartet eine Antwort, sobald Ihr Client eine Verbindung hergestellt hat):

>>>

>>> requests.get('https://api.github.com', timeout=(2, 5))

Wenn die Anforderung innerhalb von 2 Sekunden eine Verbindung herstellt und innerhalb von 5 Sekunden nach dem Herstellen der Verbindung Daten empfängt, wird die Antwort wie zuvor zurückgegeben. Wenn die Anforderung abgelaufen ist, löst die Funktion eine Ausnahme vonTimeoutaus:

import requests
from requests.exceptions import Timeout

try:
    response = requests.get('https://api.github.com', timeout=1)
except Timeout:
    print('The request timed out')
else:
    print('The request did not time out')

Ihr Programm kann die Ausnahme vonTimeoutabfangen und entsprechend reagieren.

Das Sitzungsobjekt

Bisher haben Sie sich mit APIs auf hoher Ebene fürrequestswieget()undpost()befasst. Diese Funktionen sind Abstraktionen dessen, was passiert, wenn Sie Ihre Anfragen stellen. Sie verbergen Implementierungsdetails wie die Verwaltung von Verbindungen, damit Sie sich keine Sorgen machen müssen.

Unter diesen Abstraktionen befindet sich eine Klasse namensSession. Wenn Sie Ihre Kontrolle darüber, wie Anforderungen gestellt werden, optimieren oder die Leistung Ihrer Anforderungen verbessern müssen, müssen Sie möglicherweise die InstanzSessiondirekt verwenden.

Sitzungen werden verwendet, um Parameter über Anforderungen hinweg beizubehalten. Wenn Sie beispielsweise dieselbe Authentifizierung für mehrere Anforderungen verwenden möchten, können Sie eine Sitzung verwenden:

import requests
from getpass import getpass

# By using a context manager, you can ensure the resources used by
# the session will be released after use
with requests.Session() as session:
    session.auth = ('username', getpass())

    # Instead of requests.get(), you'll use session.get()
    response = session.get('https://api.github.com/user')

# You can inspect the response just like you did before
print(response.headers)
print(response.json())

Jedes Mal, wenn Sie eine Anfrage mitsession stellen, bleiben die Anmeldeinformationen erhalten, sobald sie mit Authentifizierungsdaten initialisiert wurden.

Die primäre Leistungsoptimierung von Sitzungen erfolgt in Form von dauerhaften Verbindungen. Wenn Ihre App mitSession eine Verbindung zu einem Server herstellt, bleibt diese Verbindung in einem Verbindungspool erhalten. Wenn Ihre App erneut eine Verbindung zum selben Server herstellen möchte, wird eine Verbindung aus dem Pool wiederverwendet, anstatt eine neue herzustellen.

Max Wiederholungen

Wenn eine Anforderung fehlschlägt, möchten Sie möglicherweise, dass Ihre Anwendung dieselbe Anforderung erneut versucht. requests erledigt dies jedoch standardmäßig nicht für Sie. Um diese Funktionalität anzuwenden, müssen Sie ein benutzerdefiniertesTransport Adapter implementieren.

Mit Transportadaptern können Sie eine Reihe von Konfigurationen pro Dienst definieren, mit dem Sie interagieren. Angenommen, Sie möchten, dass alle Anforderungen anhttps://api.github.com dreimal wiederholt werden, bevor schließlichConnectionError ausgelöst werden. Sie würden einen Transportadapter erstellen, seinen Parametermax_retries festlegen und ihn in einen vorhandenenSession einbinden:

import requests
from requests.adapters import HTTPAdapter
from requests.exceptions import ConnectionError

github_adapter = HTTPAdapter(max_retries=3)

session = requests.Session()

# Use `github_adapter` for all requests to endpoints that start with this URL
session.mount('https://api.github.com', github_adapter)

try:
    session.get('https://api.github.com')
except ConnectionError as ce:
    print(ce)

Wenn SieHTTPAdapter,github_adapter ansession hängen, bleibtsession bei jeder Anforderung anhttps://api.github.com an der Konfiguration.

Zeitüberschreitungen, Transportadapter und Sitzungen dienen dazu, Ihren Code effizient und Ihre Anwendung stabil zu halten.

Fazit

Sie haben einen langen Weg zurückgelegt, um die leistungsstarkerequests-Bibliothek von Python kennenzulernen.

Sie können jetzt:

  • Stellen Sie Anforderungen mit verschiedenen HTTP-Methoden wieGET,POST undPUT

  • Passen Sie Ihre Anforderungen an, indem Sie Header, Authentifizierung, Abfragezeichenfolgen und Nachrichtentexte ändern

  • Überprüfen Sie die Daten, die Sie an den Server senden, und die Daten, die der Server an Sie zurücksendet

  • Arbeiten Sie mit der Überprüfung des SSL-Zertifikats

  • Verwenden Sierequests effektiv mitmax_retries,timeout, Sitzungen und Transportadaptern

Da Sie gelernt haben, wie manrequestsverwendet, können Sie die weite Welt der Webdienste erkunden und mithilfe der faszinierenden Daten, die sie bereitstellen, fantastische Anwendungen erstellen.