Corso
Le Application Programming Interface (API) sono mediatori software. Il loro compito è permettere alle applicazioni di comunicare tra loro. Questi mediatori discreti compaiono nella vita quotidiana, che tu lo sappia o meno. Per esempio, se oggi hai inviato un messaggio istantaneo, hai usato un’API.
Più nello specifico, le API consentono alle persone di inviare e recuperare dati tramite codice. Tuttavia, è più comune usare le API per recuperare dati. Ad esempio, puoi leggere questo post del blog perché il tuo browser ha recuperato i dati che compongono questa pagina dal server DataCamp.
Ma i server web non inviano dati a caso. Sarebbe come andare al ristorante e il cameriere ti porta un piatto a caso. Prima che il server risponda con dei dati, va fatta una richiesta per recuperarli. Questo vale sia per il cameriere al ristorante, sia per quando vuoi recuperare dei dati da un’API: invii una richiesta API a un server e questo risponderà con i dati appropriati.
In questo articolo passeremo in rassegna alcuni dei componenti principali della libreria requests e forniremo esempi di codice per aiutarti a iniziare. La requests library merita di essere imparata perché è lo standard de facto per inviare richieste HTTP in Python. Come vedrai, isola tutte le complessità dell’invio di richieste dietro una semplice API, permettendoti di concentrarti sulla comunicazione con i servizi e sul consumo dei dati nella tua applicazione.
Esegui e modifica il codice da questo tutorial online
Esegui codiceEffettuare richieste GET e POST con il modulo requests di Python
Hai fretta? Ecco la sintassi Python per effettuare una semplice richiesta GET e POST:
1. Richiesta GET
import requests
# The API endpoint
url = "https://jsonplaceholder.typicode.com/posts/1"
# A GET request to the API
response = requests.get(url)
# Print the response
print(response.json())
2. Richiesta POST
import requests
# The API endpoint
url = "https://jsonplaceholder.typicode.com/posts"
# Data to be sent
data = {
"userID": 1,
"title": "Making a POST request",
"body": "This is the data we created."
}
# A POST request to the API
response = requests.post(url, json=data)
# Print the response
print(response.json())
Capire le API REST e le loro basi HTTP
Abbiamo stabilito che le API sono mediatori software. Un altro modo di pensarle è come un tipo di interfaccia software che concede ad altre applicazioni l’accesso a dati e metodi specifici.
Una delle architetture più popolari per costruire API è il modello REpresentational State Transfer (REST). Il design architetturale REST consente al client e al server di essere implementati in modo indipendente l’uno dall’altro senza doversi conoscere a vicenda. Ciò significa che il codice su entrambi i lati può essere modificato senza preoccuparsi di come il cambiamento influenzerà l’altro.
Le API REST, quindi, seguono un insieme di linee guida pensate per semplificare la comunicazione tra software, rendendo così più semplice e logico il processo di accesso ai dati. Non preoccuparti se non conosci queste linee guida; non ti servono per iniziare – ciò che devi sapere è come i dati vengono esposti dai servizi REST.
I dati dei servizi web REST sono esposti su internet tramite un URL pubblico, accessibile inviando una richiesta HTTP.
Panoramica dei metodi di richiesta HTTP
Torniamo alla nostra analogia del ristorante: per ordinare, il cameriere si avvicina e tu dici cosa vuoi. Il cameriere passa la tua richiesta allo chef, che prepara il piatto e lo riconsegna tramite il cameriere. In altre parole, lo chef non cucinerebbe finché non riceve la richiesta.
Le API REST sono uguali: ascoltano i metodi di richiesta HTTP prima di agire. HTTP definisce un insieme di metodi di richiesta che dicono all’API quali operazioni eseguire su una determinata risorsa. Specifica come interagire con le risorse situate all’endpoint fornito.
Esistono diversi metodi HTTP, ma cinque sono comunemente usati con le API REST:
| Metodo HTTP | Descrizione |
|---|---|
| GET | Recupera dati |
| POST | Crea dati |
| PUT | Aggiorna dati esistenti |
| PATCH | Aggiorna parzialmente dati esistenti |
| DELETE | Elimina dati |
È molto probabile che, nell’analisi dei dati e nella data science, eseguirai richieste GET più di qualsiasi altro metodo. Questo perché è il metodo necessario per accedere a determinati dataset. Scopri di più nel corso di DataCamp Intermediate Importing Data in Python.
Quando invii una richiesta a un server web, l’API restituisce una risposta. Alla risposta è associato un codice di stato HTTP. Lo scopo del codice di stato è fornire informazioni aggiuntive sulla risposta, in modo che il client sappia che tipo di richiesta è stata ricevuta.
Cosa sono gli endpoint API?
Un URL definisce i dati con cui interagisci su un server web. Proprio come l’URL di una pagina web è collegato a una singola pagina, un URL di endpoint è collegato a particolari risorse all’interno di un’API. Pertanto, un endpoint può essere descritto come una posizione digitale in cui un’API riceve richieste su una specifica risorsa presente sul suo server — pensalo come l’altra estremità di un canale di comunicazione.
Per aggiungere contesto, le API REST espongono un insieme di URL pubblici a cui le applicazioni client possono effettuare richieste per accedere alle risorse del servizio web. Gli URL pubblici esposti dall’API REST sono chiamati “endpoint”.
Usare Python per effettuare richieste HTTP
Il modulo requests di Python permette agli sviluppatori di scrivere codice per interagire con le API REST. Consente di inviare richieste HTTP in Python senza doversi preoccupare delle complessità che di solito accompagnano tali attività (cioè aggiungere manualmente query string agli URL, codificare in formato form i dati PUT e POST, ecc.).
Pur essendo considerato lo standard de facto per effettuare richieste HTTP in Python, il modulo requests non fa parte della libreria standard di Python – va installato.
Il modo più semplice per installare il modulo requests è con pip:
python -m pip install requests
È sempre consigliato gestire i pacchetti Python richiesti per i diversi progetti usando ambienti virtuali; in questo modo, i pacchetti di un progetto non interferiranno né romperanno strumenti di sistema in altri progetti perché sono isolati, invece di essere installati globalmente.
Ora che abbiamo installato il modulo requests, vediamo come funziona. Segui il codice in questo DataLab workbook.
Effettuare una richiesta GET in Python
Abbiamo già stabilito che GET è uno dei metodi di richiesta HTTP più comuni che incontrerai lavorando con le API REST. Ti permette (come client) di recuperare dati dai server web.
È importante notare che GET è un’operazione in sola lettura, quindi è adatta solo per accedere a risorse esistenti e non dovrebbe essere usata per modificarle.
Per dimostrare come funziona il modulo requests, useremo JSONPlaceholder, un’API fittizia liberamente disponibile per test e prototipazione.
import requests
# The API endpoint
url = "https://jsonplaceholder.typicode.com/posts/1"
# A GET request to the API
response = requests.get(url)
# Print the response
response_json = response.json()
print(response_json)
"""
{'userId': 1, 'id': 1, 'title': 'sunt aut facere repellat provident occaecati excepturi optio reprehenderit', 'body': 'quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto'}
"""
Nel codice sopra abbiamo eseguito quanto segue:
-
Definito l’endpoint dell’API da cui recuperare i dati.
-
Usato il metodo
requests.get(url)per recuperare i dati dall’endpoint definito. -
Usato il metodo
response.json()per memorizzare i dati della risposta in un oggetto dizionario; nota che questo funziona solo perché il risultato è in formato JSON – altrimenti sarebbe stato sollevato un errore. -
L’ultimo passaggio è stampare i dati JSON della risposta.
Possiamo anche controllare il codice di stato restituito dall’API in questo modo:
# Print status code from original response (not JSON)
print(response.status_code)
"""
200
"""
Puoi anche passare argomenti a una richiesta GET in Python. Per farlo, dobbiamo modificare leggermente il codice sopra. Ecco come appare il nuovo codice:
# The API endpoint
url = "https://jsonplaceholder.typicode.com/posts/"
# Adding a payload
payload = {"id": [1, 2, 3], "userId":1}
# A get request to the API
response = requests.get(url, params=payload)
# Print the response
response_json = response.json()
for i in response_json:
print(i, "\n")
"""
{'userId': 1, 'id': 1, 'title': 'sunt aut facere repellat provident occaecati excepturi optio reprehenderit', 'body': 'quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto'}
{'userId': 1, 'id': 2, 'title': 'qui est esse', 'body': 'est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla'}
{'userId': 1, 'id': 3, 'title': 'ea molestias quasi exercitationem repellat qui ipsa sit aut', 'body': 'et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut ad\nvoluptatem doloribus vel accusantium quis pariatur\nmolestiae porro eius odio et labore et velit aut'}
"""
Ecco cosa abbiamo fatto diversamente:
-
Modificato l’endpoint dell’API. Nota che non ha più un
1alla fine. -
Definito il payload in un dizionario.
-
Passato il payload all’argomento
paramdel metodorequests.get(). -
Questo ha restituito un oggetto lista, quindi abbiamo iterato sulla lista e stampato ciascun elemento su una nuova riga.
Effettuare una richiesta POST in Python
Le richieste GET ti permettono di recuperare dati; le richieste POST ti consentono di creare nuovi dati. Vediamo come possiamo creare nuovi dati sul server JSONPlaceholder.
# Define new data to create
new_data = {
"userID": 1,
"id": 1,
"title": "Making a POST request",
"body": "This is the data we created."
}
# The API endpoint to communicate with
url_post = "https://jsonplaceholder.typicode.com/posts"
# A POST request to tthe API
post_response = requests.post(url_post, json=new_data)
# Print the response
post_response_json = post_response.json()
print(post_response_json)
"""
{'userID': 1, 'id': 101, 'title': 'Making a POST request', 'body': 'This is the data we created.'}
"""
Nel codice sopra abbiamo eseguito quanto segue:
-
Creato una nuova risorsa da aggiungere all’API JSONPlaceholder.
-
Definito l’endpoint su cui effettuare il
POSTdei nuovi dati. -
Inviata una richiesta
POSTusando il metodorequests.post(). Nota che il parametrojsonè stato impostato nel metodopost(); lo facciamo per indicare all’API che stiamo esplicitamente inviando un oggetto JSON all’URL specificato. -
Usato il metodo
response.json()per memorizzare i dati della risposta in un oggetto dizionario. -
L’ultimo passaggio è stampare i dati JSON della risposta.
Ma, aspetta!
Prima di leggere il prossimo pezzo di codice, prenditi 20 secondi per pensare a quale codice di stato restituirà l’API.
Ricorda: questa volta abbiamo creato una nuova risorsa invece di limitarci a recuperarla.
Ok, ecco qui…
# Print status code from original response (not JSON)
print(post_response.status_code)
"""
201
"""
Argomenti avanzati sulle richieste HTTP in Python
Effettuare richieste HTTP con Python è generalmente semplice; tuttavia, a volte è inevitabile richiedere una configurazione più avanzata o imbattersi in problemi. Ecco alcune sfide che potresti incontrare e come risolverle.
Autenticare le richieste HTTP
Finora, le nostre interazioni con la REST API sono state piuttosto semplici. L’API JSONPlaceholder non richiede alcuna autenticazione per iniziare a interagirci. Tuttavia, ci sono diversi casi in cui una REST API può richiedere l’autenticazione prima di concedere l’accesso a specifici endpoint – soprattutto quando tratti dati sensibili.
Per esempio, se vuoi creare integrazioni, recuperare dati e automatizzare i tuoi flussi di lavoro su GitHub, puoi farlo con la GitHub REST API. Tuttavia, molte operazioni sulla GitHub REST API richiedono l’autenticazione, come il recupero di informazioni pubbliche e private sugli utenti autenticati.
Ecco una semplice soluzione usando il modulo requests di Python:
from requests.auth import HTTPBasicAuth
private_url = "https://api.github.com/user"
github_username = "username"
token = "token"
private_url_response = requests.get(
url=private_url,
auth=HTTPBasicAuth(github_username, token)
)
private_url_response.status_code
"""
200
"""
Nel codice sopra abbiamo:
-
Importato l’oggetto
HTTPBasicAuthdarequests.auth. Questo oggetto allega l’autenticazione HTTP basic alla richiesta data — è essenzialmente come digitare nome utente e password su un sito web. -
Definito l’endpoint URL privato da accedere.
-
Istanziato una variabile con un nome utente GitHub – abbiamo anonimizzato il nome utente per privacy.
-
Istanziato una variabile con un personal access token di GitHub per l’autenticazione.
-
Recuperato i dati dal nostro endpoint e memorizzati nella variabile
private_url_response. -
Mostrato il codice di stato.
Gestire gli errori delle richieste HTTP
Ci sono casi in cui le richieste a un’API non vanno come previsto. Possono intervenire diversi fattori, lato client o lato server. Indipendentemente dalla causa, l’esito è sempre lo stesso: la richiesta fallisce.
Quando usi le API REST, è sempre una buona idea rendere il tuo codice resiliente. Tuttavia, prima di poter scrivere codice robusto, devi capire come gestire gli errori segnalati quando le cose non vanno secondo i piani.
Per questa dimostrazione, torniamo all’API JSONPlaceholder. Inizieremo scrivendo del codice e poi spiegheremo cosa sta succedendo.
# A deliberate typo is made in the endpoint "postz" instead of "posts"
url = "https://jsonplaceholder.typicode.com/postz"
# Attempt to GET data from provided endpoint
try:
response = requests.get(url)
response.raise_for_status()
# If the request fails (404) then print the error.
except requests.exceptions.HTTPError as error:
print(error)
"""
404 Client Error: Not Found for url: https://jsonplaceholder.typicode.com/postz
"""
Nel codice sopra:
-
Abbiamo definito l’endpoint di JSONPlaceholder da cui recuperare i dati, ma abbiamo inserito volutamente un errore di battitura nell’URL – questo genererà un errore 404.
-
Abbiamo usato la gestione delle eccezioni integrata di Python per
tryeexcept(catturare) eventuali errori che si verificano tentando di visitare l’endpoint di JSONPlaceholder. Nota che il metodoraise_for_status()è ciò che viene usato per restituire un oggettoHTTPErrorquando si verifica un errore durante il processo. -
E infine, abbiamo stampato l’errore che è stato sollevato.
Sebbene in questo caso abbiamo mostrato come gestire i codici di stato di errore 404, lo stesso schema può essere usato per gestire qualsiasi codice di stato HTTP.
Gestire un numero eccessivo di redirect
I codici di stato HTTP nella serie 3xx indicano che il client è stato reindirizzato e deve eseguire altre azioni per completare la richiesta. Tuttavia, questo a volte può portare a un loop di redirect infinito.
Il modulo requests di Python fornisce l’oggetto TooManyRedirects per gestire questo problema, come segue:
"""
Note: The code here will not raise an error
but the structure is how you would hand a case where there
are multiple redirects
"""
url = "https://jsonplaceholder.typicode.com/posts"
try:
response = requests.get(url)
response.raise_for_status()
except requests.exceptions.TooManyRedirects as error:
print(error)
Puoi anche impostare il numero massimo di redirect come parametro del tuo metodo di richiesta HTTP:
# Solution 2
url = "https://jsonplaceholder.typicode.com/posts"
session = requests.Session()
session.max_redirects = 3
response = session.get(url)
Un’altra opzione è disabilitare completamente i redirect:
# Solution 3
url = "https://jsonplaceholder.typicode.com/posts"
session = requests.Session()
session.allow_redirects = False
response = session.get(url)
Gestire gli errori di connessione nelle richieste HTTP
Questi sono altri tipi di errori che potresti incontrare quando tenti di inviare richieste a un server. Ci sono diversi motivi per cui potresti non ricevere una risposta dal server (ad es. errore DNS, connessione rifiutata, problemi di connessione a internet, ecc.), ma l’esito è coerente: viene generato un errore di connessione.
Puoi usare l’oggetto eccezione ConnectionError del modulo requests per intercettare questi problemi e gestirli di conseguenza.
Ecco come apparirebbe il codice:
"""
Note: The code here will not raise an error
but the structure is how you would hand a case where there
is a connection error.
"""
url = "https://jsonplaceholder.typicode.com/posts"
try:
response = requests.get(url)
except requests.ConnectionError as error:
print(error)
Gestire il timeout delle richieste HTTP
Quando il server API accetta la tua connessione ma non riesce a completare la richiesta entro il tempo consentito, otterrai un “errore di timeout”.
Mostreremo come gestire questo caso impostando il parametro timeout nel metodo requests.get() su un valore estremamente piccolo; questo genererà un errore, che gestiremo usando l’oggetto requests.Timeout.
url = "https://jsonplaceholder.typicode.com/posts"
try:
response = requests.get(url, timeout=0.0001)
except requests.Timeout as error:
print(error)
La soluzione più semplice agli errori di timeout è impostare timeout più lunghi. Altre soluzioni possono includere l’ottimizzazione delle richieste, l’inserimento di un ciclo di retry negli script o l’esecuzione di chiamate API asincrone – una tecnica che permette al tuo software di avviare un’attività potenzialmente lunga rimanendo reattivo ad altri eventi invece di aspettare che l’attività sia completata.
Conclusioni
In questo tutorial abbiamo visto cosa sono le API ed esplorato un’architettura comune per le API chiamata REST. Abbiamo anche esaminato i metodi HTTP e come possiamo usare la libreria requests di Python per interagire con i servizi web.
Dai un’occhiata ai seguenti corsi per sviluppare le tue competenze in data science:
FAQs
Come puoi gestire header personalizzati nelle richieste HTTP in Python?
Puoi aggiungere header personalizzati alle tue richieste HTTP passando un dizionario di header al parametro headers nella tua richiesta. Per esempio:
import requests
url = "https://jsonplaceholder.typicode.com/posts"
headers = {
"Authorization": "Bearer YOUR_ACCESS_TOKEN",
"Content-Type": "application/json"
}
response = requests.get(url, headers=headers)
print(response.json())
Quali sono i vantaggi dell’uso di un oggetto session nel modulo requests?
L’utilizzo di un oggetto Session nel modulo requests offre diversi vantaggi, tra cui:
- Connessioni persistenti: mantiene una connessione tra più richieste, migliorando le prestazioni.
- Impostazioni a livello di sessione: ti permette di impostare header, cookie e parametri una sola volta per tutte le richieste effettuate tramite la sessione.
- Persistenza dei cookie: gestisce automaticamente i cookie, mantenendoli tra le richieste.
Ecco un esempio:
import requests
session = requests.Session()
session.headers.update({"Authorization": "Bearer YOUR_ACCESS_TOKEN"})
response = session.get("https://jsonplaceholder.typicode.com/posts")
print(response.json())
Come si invia un file con una richiesta POST in Python?
Puoi inviare un file con una richiesta POST passando un dizionario al parametro files. Per esempio:
import requests
url = "https://example.com/upload"
file_path = "/path/to/your/file.txt"
with open(file_path, 'rb') as file:
files = {'file': file}
response = requests.post(url, files=files)
print(response.status_code)
Come puoi configurare il modulo requests per usare i proxy?
Puoi configurare i proxy nel modulo requests passando un dizionario al parametro proxies. Per esempio:
import requests
url = "https://jsonplaceholder.typicode.com/posts"
proxies = {
"http": "http://10.10.1.10:3128/",
"https": "http://10.10.1.10:1080/",
}
response = requests.get(url, proxies=proxies)
print(response.json())
Come puoi gestire i timeout quando effettui richieste HTTP con il modulo requests di Python?
Puoi gestire i timeout specificando il parametro timeout nella tua richiesta. Questo parametro accetta un valore in secondi. Per esempio:
import requests
url = "https://jsonplaceholder.typicode.com/posts"
try:
response = requests.get(url, timeout=5) # Timeout dopo 5 secondi
print(response.json())
except requests.Timeout:
print("La richiesta è andata in timeout")
