Introduction au Module Requests
Le module Requests pour Python est une bibliothèque HTTP conviviale et élégante, largement utilisée dans les applications d'exploration web (web scraping) et les enteractions avec les API. Conçu pour simplifier l'envoi de requêtes HTTP, il permet aux développeurs de simuler le comportement d'un navigateur web et de récupérer facilement des données.
Installation
L'installation de Requests est simple via pip :
pip install requests
Cycle de Vie d'une Requête HTTP avec Requests
L'interaction typique avec le module Requests suit ces étapes fondamentales :
- Définir l'URL Cible : Spécifier l'adresse de la ressource web à interroger.
- Exécuter la Requête : Envoyer une requête HTTP (GET, POST, etc.) à l'URL définie.
- Traiter la Réponse : Récupérer et analyser les données renvoyées par le serveur.
- Stocker les Données : Sauvegarder les informations extraites pour une utilisation future.
Exemple 1 : Récupération du Contenu d'une Page Web Statique
Commençons par un exemple simple : récupérer le code source de la page d'accueil de Sogou. Cet exemple illustre les étapes de base pour effectuer une requête GET et enregistrer le contenu HTML.
import requests
import os # Pour des opérations sur les fichiers, comme la vérification de l'existence
def telecharger_page_html(url_cible: str, nom_fichier_destination: str):
"""
Récupère le contenu HTML d'une URL donnée et le sauvegarde dans un fichier spécifié.
"""
print(f"Tentative de téléchargement de: {url_cible}")
try:
# 1. Spécifier l'URL (déjà fait via l'argument url_cible)
# 2. Effectuer la requête GET
# requests.get() retourne un objet Response
reponse_http = requests.get(url_cible)
# Vérifier si la requête a réussi (code d'état 200)
reponse_http.raise_for_status() # Lève une exception HTTPError pour les codes d'erreur 4xx/5xx
# 3. Récupérer les données de la réponse
# .text contient le contenu de la réponse sous forme de chaîne de caractères
contenu_page = reponse_http.text
# 4. Persister les données
chemin_complet = os.path.join(".", nom_fichier_destination)
with open(chemin_complet, "w", encoding="utf-8") as fichier_sortie:
fichier_sortie.write(contenu_page)
print(f"Contenu de la page sauvegardé dans '{chemin_complet}' avec succès.")
except requests.exceptions.RequestException as e:
print(f"Une erreur s'est produite lors de la requête ou du téléchargement: {e}")
except IOError as e:
print(f"Erreur d'écriture du fichier '{nom_fichier_destination}': {e}")
if __name__ == "__main__":
URL_ACCUEIL_SOGOU = "https://www.sogou.com/"
NOM_FICHIER_SOGOU = "page_sogou.html"
telecharger_page_html(URL_ACCUEIL_SOGOU, NOM_FICHIER_SOGOU)
Exemple 2 : Collecteur Web Basique avec Paramètres Dynamiques et Entêtes Personnalisées
Lorsqu'on effectue des recherches ou interagit avec des formulaires, les requêtes inlcuent souvent des paramètres. De plus, pour éviter d'être bloqué par les serveurs, il est crucial d'envoyer des entêtes HTTP simulant un navigateur (User-Agent).
Pour gérer les paramètres dynamiques :
- Organisez les paramètres dans un dictionnaire Python.
- Passez ce dictionnaire à l'argument
paramsde la méthoderequests.get(). Requests se chargera d'encoder les paramètres dans l'URL. - Pour l'usurpation d'identité (User-Agent spoofing), créez un dictionnaire d'entêtes et passez-le à l'argument
headers.
import requests
import os
def effectuer_recherche_web(terme_recherche: str):
"""
Effectue une recherche sur Sogou avec un terme donné, gère les paramètres dynamiques
et l'usurpation de User-Agent, puis sauvegarde le résultat.
"""
url_base_recherche = "https://www.sogou.com/web"
# Définition des entêtes HTTP pour simuler un navigateur web standard
entetes_http = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36",
"Accept-Language": "fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7",
"Accept-Encoding": "gzip, deflate, br",
"Connection": "keep-alive"
}
# Les paramètres de la requête sont encapsulés dans un dictionnaire
parametres_url = {
'query': terme_recherche
}
print(f"Recherche de '{terme_recherche}' sur Sogou...")
try:
# Exécution de la requête GET avec les paramètres et les entêtes
reponse_search = requests.get(
url=url_base_recherche,
params=parametres_url,
headers=entetes_http
)
reponse_search.raise_for_status() # Lève une exception si le statut HTTP est une erreur
# Correction de l'encodage si Requests ne le détecte pas correctement
# Pour les sites chinois, 'gb2312' ou 'gbk' sont parfois nécessaires
# Si la détection automatique échoue, on peut forcer: reponse_search.encoding = 'utf-8'
contenu_resultat = reponse_search.text
# Création d'un nom de fichier unique basé sur le terme de recherche
nom_fichier_resultat = f"recherche_sogou_{terme_recherche.replace(' ', '_')}.html"
chemin_sortie = os.path.join(".", nom_fichier_resultat)
with open(chemin_sortie, "w", encoding="utf-8") as fichier:
fichier.write(contenu_resultat)
print(f"Résultat de la recherche pour '{terme_recherche}' sauvegardé dans '{chemin_sortie}'.")
except requests.exceptions.RequestException as e:
print(f"Erreur lors de la recherche sur Sogou: {e}")
except IOError as e:
print(f"Erreur d'écriture du fichier '{nom_fichier_resultat}': {e}")
if __name__ == "__main__":
mot_cle_utilisateur = input("Veuillez entrer un mot-clé pour la recherche Sogou : ")
effectuer_recherche_web(mot_cle_utilisateur)
Note sur l'Usurpation de User-Agent et l'Encodage : Les serveurs web utilisent l'entête User-Agent pour identifier le client effectuant la requête. Sans cette entête, une requête est souvent identifiée comme celle d'un bot et peut être bloquée ou redirigée vers une page d'erreur. De plus, l'encodage correct (response.encoding) est essentiel pour afficher correctement les caractères spéciaux et éviter le charabia.
Exemple 3 : Récupération de Données JSON à partir d'une API (Douban Movies)
De nombreux sites web modernes chargent des données dynamiquement via des requêtes AJAX qui renvoient souvent des réponses au format JSON. Requests simplifie grandement la manipulation de ces données grâce à sa méthode .json().
import requests
def recuperer_films_douban(type_film_id: str = '5', nombre_limite: int = 20, decalage: int = 0):
"""
Récupère une liste de films depuis l'API Douban Movies et affiche leurs titres et scores.
Args:
type_film_id (str): ID du type de film (e.g., '5' pour Action).
nombre_limite (int): Nombre maximal de films à récupérer par requête.
decalage (int): Point de départ pour la pagination (offset).
"""
api_endpoint = "https://movie.douban.com/j/chart/top_list"
# Entêtes pour simuler une requête AJAX depuis un navigateur
entetes_api = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36",
"Accept": "application/json, text/javascript, */*; q=0.01",
"X-Requested-With": "XMLHttpRequest" # Entête indiquant une requête AJAX
}
# Paramètres de la requête API pour filtrer et paginer les résultats
parametres_api = {
'type': type_film_id,
'interval_id': '100:90', # Intervalle de score, ex: 9.0-10.0
'action': '', # Paramètre souvent présent mais vide
'start': str(decalage), # Début des résultats (pour la pagination)
'limit': str(nombre_limite) # Nombre de résultats par page
}
print(f"Récupération de {nombre_limite} films (type ID: {type_film_id}, à partir de l'index: {decalage})...")
try:
# Envoi de la requête GET à l'API Douban
reponse_api = requests.get(url=api_endpoint, headers=entetes_api, params=parametres_api)
reponse_api.raise_for_status() # Gérer les erreurs HTTP
# .json() convertit automatiquement la chaîne JSON de la réponse en un objet Python (liste/dictionnaire)
donnees_films = reponse_api.json()
if not donnees_films:
print("Aucun film trouvé ou fin des résultats pour les critères donnés.")
return
print("\n--- Films Récupérés depuis Douban ---")
for film_data in donnees_films:
# Utilisation de .get() pour éviter KeyError si une clé est manquante
titre_film = film_data.get("title", "Titre inconnu")
score_film = film_data.get("score", "N/A")
print(f"- Titre: {titre_film}, Score: {score_film}")
except requests.exceptions.RequestException as e:
print(f"Erreur lors de la récupération des films Douban: {e}")
except ValueError: # Peut se produire si la réponse n'est pas un JSON valide
print("Erreur: La réponse de l'API n'est pas un format JSON valide.")
if __name__ == "__main__":
# Exemple : Récupérer les 20 premiers films d'action (type '5')
recuperer_films_douban(type_film_id='5', nombre_limite=20)
# Pour récupérer la page suivante (les 20 films suivants)
# recuperer_films_douban(type_film_id='5', nombre_limite=20, decalage=20)
Exemple 4 : Traitement de la Pagination avec des Requêtes POST (KFC Stores)
Pour les sites qui utilisent des requêtes POST pour soumettre des formulaires ou charger des données paginées, le processus est similaire, mais les paramètres sont passés via l'argument data au lieu de params.
Cet exemple montre comment récupérer les emplacements des restaurants KFC à Guanghzou, en gérant la pagination pour parcourir plusieurs pages de résultats.
import requests
import json # Utile si l'on souhaite inspecter le JSON brut de la réponse
def obtenir_emplacements_kfc(nom_ville: str, nombre_pages: int = 3):
"""
Récupère les noms et adresses des restaurants KFC pour une ville donnée,
en parcourant un nombre spécifié de pages de résultats via des requêtes POST.
"""
url_api_kfc_magasins = "http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword"
# Entêtes HTTP nécessaires pour une requête POST, souvent avec Content-Type
entetes_post_kfc = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36",
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"X-Requested-With": "XMLHttpRequest" # Indique une requête AJAX
}
print(f"Recherche des restaurants KFC à '{nom_ville}' sur {nombre_pages} pages...")
liste_restaurants_trouves = []
# Boucle pour itérer sur les différentes pages de résultats
for index_page in range(1, nombre_pages + 1):
# Données du formulaire à envoyer avec la requête POST
# 'keyword' est le terme de recherche, 'pageIndex' est le numéro de page
payload_formulaire = {
'cname': '',
'pid': '',
'keyword': nom_ville, # La ville à rechercher
'pageIndex': str(index_page), # Le numéro de la page actuelle
'pageSize': '10' # Nombre de résultats par page
}
print(f" Récupération de la page {index_page}...")
try:
# Exécution de la requête POST avec les données du formulaire et les entêtes
reponse_kfc = requests.post(
url=url_api_kfc_magasins,
data=payload_formulaire,
headers=entetes_post_kfc
)
reponse_kfc.raise_for_status() # Gérer les erreurs HTTP
# La réponse est un JSON contenant un tableau de résultats sous la clé "Table1"
donnees_json_kfc = reponse_kfc.json()
# Extraire la liste des restaurants de la clé "Table1"
restaurants_page_actuelle = donnees_json_kfc.get("Table1", [])
if not restaurants_page_actuelle:
print(f" Aucun restaurant trouvé sur la page {index_page}. Arrêt de la pagination.")
break # Arrêter la boucle si une page est vide
for resto_info in restaurants_page_actuelle:
nom_resto = resto_info.get("storeName", "Nom Inconnu")
adresse_detaillee = resto_info.get("addressDetail", "Adresse Inconnue")
liste_restaurants_trouves.append((nom_resto, adresse_detaillee))
print(f" - {nom_resto}: {adresse_detaillee}")
except requests.exceptions.RequestException as e:
print(f" Erreur lors de la récupération de la page {index_page}: {e}")
break # Arrêter en cas d'erreur de requête
except ValueError:
print(f" Erreur de décodage JSON pour la page {index_page}.")
break # Arrêter si la réponse n'est pas un JSON valide
print(f"\nTotal des restaurants KFC trouvés à '{nom_ville}' : {len(liste_restaurants_trouves)}")
# La liste 'liste_restaurants_trouves' contient tous les restaurants collectés
# Elle peut être utilisée pour une sauvegarde ou un traitement ultérieur.
if __name__ == "__main__":
# Exemple : Récupérer les 3 premières pages de restaurants KFC à '广州' (Guangzhou)
obtenir_emplacements_kfc("广州", nombre_pages=3)
# Pour une autre ville ou plus de pages, modifiez les arguments:
# obtenir_emplacements_kfc("上海", nombre_pages=5)