Comment analyser le contenu de la réponse d'un appel requests en Python

PythonPythonBeginner
Pratiquer maintenant

💡 Ce tutoriel est traduit par l'IA à partir de la version anglaise. Pour voir la version originale, vous pouvez cliquer ici

Introduction

La bibliothèque Python requests est un outil puissant pour interagir avec les services web et les API. Dans ce tutoriel, vous apprendrez à envoyer des requêtes HTTP et à analyser les données de réponse en utilisant Python. À la fin de ce lab, vous serez capable d'extraire des informations précieuses de différents types de réponses d'API, ce qui vous permettra de construire des applications basées sur les données et d'automatiser les interactions web.

Installation de la bibliothèque Requests et réalisation d'une requête de base

Dans cette première étape, nous allons installer la bibliothèque Python requests et effectuer notre première requête HTTP pour récupérer des données d'une API publique.

Installation de Requests

La bibliothèque requests est un package tiers qui doit être installé en utilisant pip, l'installateur de packages de Python. Commençons par l'installer :

pip install requests

Vous devriez voir une sortie confirmant que requests a été installé avec succès.

Réalisation de votre première requête HTTP

Maintenant, créons un fichier Python pour effectuer une simple requête HTTP. Dans le WebIDE, créez un nouveau fichier appelé basic_request.py dans le répertoire /home/labex/project.

Ajoutez le code suivant au fichier :

import requests

## Make a GET request to a public API
response = requests.get("https://jsonplaceholder.typicode.com/todos/1")

## Print the status code
print(f"Status code: {response.status_code}")

## Print the raw response content
print("\nRaw response content:")
print(response.text)

## Print the response headers
print("\nResponse headers:")
for header, value in response.headers.items():
    print(f"{header}: {value}")

Ce code effectue une requête GET vers un point de terminaison d'API d'exemple et affiche des informations sur la réponse.

Comprendre l'objet Response

Exécutons le code pour voir quelles informations nous obtenons en retour. Dans le terminal, exécutez :

python basic_request.py

Vous devriez voir une sortie similaire à celle-ci :

Status code: 200

Raw response content:
{
  "userId": 1,
  "id": 1,
  "title": "delectus aut autem",
  "completed": false
}

Response headers:
Date: Mon, 01 Jan 2023 12:00:00 GMT
Content-Type: application/json; charset=utf-8
...

L'objet response contient plusieurs attributs importants :

  • status_code: Code de statut HTTP (200 signifie succès)
  • text: Le contenu de la réponse sous forme de chaîne de caractères
  • headers: Un dictionnaire des en-têtes de réponse

Lorsque vous travaillez avec des requêtes web, ces attributs vous aident à comprendre la réponse du serveur et à la gérer de manière appropriée.

Codes de statut HTTP

Les codes de statut HTTP indiquent si une requête a réussi ou a échoué :

  • 2xx (comme 200) : Succès
  • 3xx (comme 301) : Redirection
  • 4xx (comme 404) : Erreurs client
  • 5xx (comme 500) : Erreurs serveur

Modifions notre code pour vérifier une réponse réussie. Créez un nouveau fichier appelé check_status.py avec ce contenu :

import requests

try:
    ## Make a GET request to a valid URL
    response = requests.get("https://jsonplaceholder.typicode.com/todos/1")

    ## Check if the request was successful
    if response.status_code == 200:
        print("Request successful!")
    else:
        print(f"Request failed with status code: {response.status_code}")

    ## Try an invalid URL
    invalid_response = requests.get("https://jsonplaceholder.typicode.com/invalid")
    print(f"Invalid URL status code: {invalid_response.status_code}")

except requests.exceptions.RequestException as e:
    print(f"An error occurred: {e}")

Exécutez ce code pour voir comment différentes URL renvoient différents codes de statut :

python check_status.py

Vous devriez voir que l'URL valide renvoie le code de statut 200, tandis que l'URL invalide renvoie le code de statut 404.

Analyse des données de réponse JSON

De nombreuses API modernes renvoient des données au format JSON (JavaScript Object Notation). Dans cette étape, vous apprendrez à analyser les réponses JSON et à travailler avec les données en Python.

Comprendre JSON

JSON est un format d'échange de données léger, facile à lire et à écrire pour les humains, et facile à analyser et à générer pour les machines. Il est basé sur des paires clé-valeur, similaires aux dictionnaires Python.

Voici un exemple d'objet JSON :

{
  "name": "John Doe",
  "age": 30,
  "email": "[email protected]",
  "is_active": true,
  "hobbies": ["reading", "swimming", "cycling"]
}

Analyse des réponses JSON

La bibliothèque requests facilite l'analyse des réponses JSON en utilisant la méthode .json(). Créons un nouveau fichier appelé parse_json.py et ajoutons le code suivant :

import requests

## Make a request to a GitHub API endpoint that returns JSON data
response = requests.get("https://api.github.com/users/python")

## Check if the request was successful
if response.status_code == 200:
    ## Parse the JSON response
    data = response.json()

    ## Print the parsed data
    print("Parsed JSON data:")
    print(f"Username: {data['login']}")
    print(f"Name: {data.get('name', 'Not provided')}")
    print(f"Followers: {data['followers']}")
    print(f"Public repositories: {data['public_repos']}")

    ## Print the type to verify it's a Python dictionary
    print(f"\nType of parsed data: {type(data)}")

    ## Access nested data
    print("\nAccessing specific elements:")
    print(f"Avatar URL: {data['avatar_url']}")
else:
    print(f"Request failed with status code: {response.status_code}")

Exécutez ce script pour voir comment les données JSON sont analysées en un dictionnaire Python :

python parse_json.py

Vous devriez voir une sortie qui affiche des informations sur l'utilisateur GitHub, y compris son nom d'utilisateur, le nombre de followers et le nombre de dépôts.

Travailler avec des listes de données

De nombreuses API renvoient des listes d'objets. Voyons comment gérer ce type de réponse. Créez un fichier appelé json_list.py avec ce contenu :

import requests

## Make a request to an API that returns a list of posts
response = requests.get("https://jsonplaceholder.typicode.com/posts")

## Check if the request was successful
if response.status_code == 200:
    ## Parse the JSON response (this will be a list of posts)
    posts = response.json()

    ## Print the total number of posts
    print(f"Total posts: {len(posts)}")

    ## Print details of the first 3 posts
    print("\nFirst 3 posts:")
    for i, post in enumerate(posts[:3], 1):
        print(f"\nPost #{i}")
        print(f"User ID: {post['userId']}")
        print(f"Post ID: {post['id']}")
        print(f"Title: {post['title']}")
        print(f"Body: {post['body'][:50]}...")  ## Print just the beginning of the body
else:
    print(f"Request failed with status code: {response.status_code}")

Exécutez ce script pour voir comment traiter une liste d'objets JSON :

python json_list.py

Vous devriez voir des informations sur les trois premiers articles, y compris leurs titres et le début de leur contenu.

Gestion des erreurs avec l'analyse JSON

Parfois, une réponse peut ne pas contenir de données JSON valides. Voyons comment gérer cela avec élégance. Créez un fichier appelé json_error.py avec ce code :

import requests
import json

def get_and_parse_json(url):
    try:
        ## Make the request
        response = requests.get(url)

        ## Check if the request was successful
        response.raise_for_status()

        ## Try to parse the JSON
        try:
            data = response.json()
            return data
        except json.JSONDecodeError:
            print(f"Response from {url} is not valid JSON")
            print(f"Raw response: {response.text[:100]}...")  ## Print part of the raw response
            return None

    except requests.exceptions.HTTPError as e:
        print(f"HTTP error: {e}")
    except requests.exceptions.RequestException as e:
        print(f"Request error: {e}")

    return None

## Test with a valid JSON endpoint
json_data = get_and_parse_json("https://jsonplaceholder.typicode.com/posts/1")
if json_data:
    print("\nValid JSON response:")
    print(f"Title: {json_data['title']}")

## Test with a non-JSON endpoint
html_data = get_and_parse_json("https://www.example.com")
if html_data:
    print("\nThis should not print as example.com returns HTML, not JSON")
else:
    print("\nAs expected, could not parse HTML as JSON")

Exécutez ce script pour voir comment gérer différents types de réponses :

python json_error.py

Vous devriez voir que le code gère avec succès les réponses JSON valides et les réponses non-JSON.

Analyse du contenu HTML avec BeautifulSoup

Lorsque vous travaillez avec des données web, vous rencontrerez souvent des réponses HTML. Pour l'analyse HTML, la bibliothèque BeautifulSoup de Python est un excellent outil. Dans cette étape, nous allons apprendre à extraire des informations des réponses HTML.

Installation de BeautifulSoup

Tout d'abord, installons BeautifulSoup et son analyseur HTML :

pip install beautifulsoup4

Analyse HTML de base

Créons un fichier appelé parse_html.py pour récupérer et analyser une page web :

import requests
from bs4 import BeautifulSoup

## Make a request to a webpage
url = "https://www.example.com"
response = requests.get(url)

## Check if the request was successful
if response.status_code == 200:
    ## Parse the HTML content
    soup = BeautifulSoup(response.text, 'html.parser')

    ## Extract the page title
    title = soup.title.text
    print(f"Page title: {title}")

    ## Extract all paragraphs
    paragraphs = soup.find_all('p')
    print(f"\nNumber of paragraphs: {len(paragraphs)}")

    ## Print the text of the first paragraph
    if paragraphs:
        print(f"\nFirst paragraph text: {paragraphs[0].text.strip()}")

    ## Extract all links
    links = soup.find_all('a')
    print(f"\nNumber of links: {len(links)}")

    ## Print the href attribute of the first link
    if links:
        print(f"First link href: {links[0].get('href')}")

else:
    print(f"Request failed with status code: {response.status_code}")

Exécutez ce script pour voir comment extraire des informations de base d'une page HTML :

python parse_html.py

Vous devriez voir une sortie affichant le titre de la page, le nombre de paragraphes, le texte du premier paragraphe, le nombre de liens et l'URL du premier lien.

Recherche d'éléments spécifiques

Voyons maintenant comment trouver des éléments spécifiques en utilisant des sélecteurs CSS. Créez un fichier appelé html_selectors.py :

import requests
from bs4 import BeautifulSoup

## Make a request to a webpage with more complex structure
url = "https://quotes.toscrape.com/"
response = requests.get(url)

## Check if the request was successful
if response.status_code == 200:
    ## Parse the HTML content
    soup = BeautifulSoup(response.text, 'html.parser')

    ## Find all quote elements
    quote_elements = soup.select('.quote')
    print(f"Number of quotes found: {len(quote_elements)}")

    ## Process the first 3 quotes
    print("\nFirst 3 quotes:")
    for i, quote_element in enumerate(quote_elements[:3], 1):
        ## Extract the quote text
        text = quote_element.select_one('.text').text

        ## Extract the author
        author = quote_element.select_one('.author').text

        ## Extract the tags
        tags = [tag.text for tag in quote_element.select('.tag')]

        ## Print the information
        print(f"\nQuote #{i}")
        print(f"Text: {text}")
        print(f"Author: {author}")
        print(f"Tags: {', '.join(tags)}")

else:
    print(f"Request failed with status code: {response.status_code}")

Exécutez ce script pour voir comment utiliser les sélecteurs CSS pour extraire des éléments spécifiques :

python html_selectors.py

Vous devriez voir une sortie affichant des informations sur les trois premières citations, y compris le texte de la citation, l'auteur et les balises.

Construction d'un simple Web Scraper

Assemblons le tout pour construire un simple web scraper qui extrait des données structurées d'une page web. Créez un fichier appelé quotes_scraper.py :

import requests
from bs4 import BeautifulSoup
import json
import os

def scrape_quotes_page(url):
    ## Make a request to the webpage
    response = requests.get(url)

    ## Check if the request was successful
    if response.status_code != 200:
        print(f"Request failed with status code: {response.status_code}")
        return None

    ## Parse the HTML content
    soup = BeautifulSoup(response.text, 'html.parser')

    ## Extract all quotes
    quotes = []
    for quote_element in soup.select('.quote'):
        ## Extract the quote text
        text = quote_element.select_one('.text').text.strip('"')

        ## Extract the author
        author = quote_element.select_one('.author').text

        ## Extract the tags
        tags = [tag.text for tag in quote_element.select('.tag')]

        ## Add the quote to our list
        quotes.append({
            'text': text,
            'author': author,
            'tags': tags
        })

    ## Check if there's a next page
    next_page = soup.select_one('.next a')
    next_page_url = None
    if next_page:
        next_page_url = 'https://quotes.toscrape.com' + next_page['href']

    return {
        'quotes': quotes,
        'next_page': next_page_url
    }

## Scrape the first page
result = scrape_quotes_page('https://quotes.toscrape.com/')

if result:
    ## Print information about the quotes found
    quotes = result['quotes']
    print(f"Found {len(quotes)} quotes on the first page")

    ## Print the first 2 quotes
    print("\nFirst 2 quotes:")
    for i, quote in enumerate(quotes[:2], 1):
        print(f"\nQuote #{i}")
        print(f"Text: {quote['text']}")
        print(f"Author: {quote['author']}")
        print(f"Tags: {', '.join(quote['tags'])}")

    ## Save the quotes to a JSON file
    output_dir = '/home/labex/project'
    with open(os.path.join(output_dir, 'quotes.json'), 'w') as f:
        json.dump(quotes, f, indent=2)

    print(f"\nSaved {len(quotes)} quotes to {output_dir}/quotes.json")

    ## Print information about the next page
    if result['next_page']:
        print(f"\nNext page URL: {result['next_page']}")
    else:
        print("\nNo next page available")

Exécutez ce script pour extraire des citations d'un site web :

python quotes_scraper.py

Vous devriez voir une sortie affichant des informations sur les citations trouvées sur la première page, et les citations seront enregistrées dans un fichier JSON appelé quotes.json.

Vérifiez le fichier JSON pour voir les données structurées :

cat quotes.json

Le fichier doit contenir un tableau JSON d'objets de citation, chacun avec des propriétés de texte, d'auteur et de balises.

Travailler avec le contenu de réponse binaire

Jusqu'à présent, nous nous sommes concentrés sur les réponses textuelles telles que JSON et HTML. Cependant, la bibliothèque requests peut également gérer le contenu binaire tel que les images, les PDF et autres fichiers. Dans cette étape, nous allons apprendre à télécharger et à traiter du contenu binaire.

Télécharger une image

Commençons par télécharger une image. Créez un fichier appelé download_image.py :

import requests
import os

## URL of an image to download
image_url = "https://httpbin.org/image/jpeg"

## Make a request to get the image
response = requests.get(image_url)

## Check if the request was successful
if response.status_code == 200:
    ## Get the content type
    content_type = response.headers.get('Content-Type', '')
    print(f"Content-Type: {content_type}")

    ## Check if the content is an image
    if 'image' in content_type:
        ## Create a directory to save the image if it doesn't exist
        output_dir = '/home/labex/project/downloads'
        os.makedirs(output_dir, exist_ok=True)

        ## Save the image to a file
        image_path = os.path.join(output_dir, 'sample_image.jpg')
        with open(image_path, 'wb') as f:
            f.write(response.content)

        ## Print information about the saved image
        print(f"Image saved to: {image_path}")
        print(f"Image size: {len(response.content)} bytes")
    else:
        print("The response does not contain an image")
else:
    print(f"Request failed with status code: {response.status_code}")

Exécutez ce script pour télécharger une image :

python download_image.py

Vous devriez voir une sortie confirmant que l'image a été téléchargée et enregistrée dans /home/labex/project/downloads/sample_image.jpg.

Télécharger un fichier avec une barre de progression

Lors du téléchargement de fichiers volumineux, il peut être utile d'afficher un indicateur de progression. Créons un script qui affiche la progression du téléchargement. Créez un fichier appelé download_with_progress.py :

import requests
import os
import sys

def download_file(url, filename):
    ## Make a request to get the file
    ## Stream the response to handle large files efficiently
    response = requests.get(url, stream=True)

    ## Check if the request was successful
    if response.status_code != 200:
        print(f"Request failed with status code: {response.status_code}")
        return False

    ## Get the total file size if available
    total_size = int(response.headers.get('Content-Length', 0))
    if total_size:
        print(f"Total file size: {total_size/1024:.2f} KB")
    else:
        print("Content-Length header not found. Unable to determine file size.")

    ## Create a directory to save the file if it doesn't exist
    os.makedirs(os.path.dirname(filename), exist_ok=True)

    ## Download the file in chunks and show progress
    print(f"Downloading {url} to {filename}...")

    ## Initialize variables for progress tracking
    downloaded = 0
    chunk_size = 8192  ## 8 KB chunks

    ## Open the file for writing
    with open(filename, 'wb') as f:
        ## Iterate through the response chunks
        for chunk in response.iter_content(chunk_size=chunk_size):
            if chunk:  ## Filter out keep-alive chunks
                f.write(chunk)
                downloaded += len(chunk)

                ## Calculate and display progress
                if total_size:
                    percent = downloaded * 100 / total_size
                    sys.stdout.write(f"\rProgress: {percent:.1f}% ({downloaded/1024:.1f} KB)")
                    sys.stdout.flush()
                else:
                    sys.stdout.write(f"\rDownloaded: {downloaded/1024:.1f} KB")
                    sys.stdout.flush()

    ## Print a newline to ensure the next output starts on a new line
    print()

    return True

## URL of a file to download
file_url = "https://speed.hetzner.de/100MB.bin"

## Path where the file will be saved
output_path = '/home/labex/project/downloads/test_file.bin'

## Download the file
success = download_file(file_url, output_path)

if success:
    ## Get file stats
    file_size = os.path.getsize(output_path)
    print(f"\nDownload complete!")
    print(f"File saved to: {output_path}")
    print(f"File size: {file_size/1024/1024:.2f} MB")
else:
    print("\nDownload failed.")

Exécutez ce script pour télécharger un fichier avec le suivi de la progression :

python download_with_progress.py

Vous verrez une barre de progression se mettre à jour au fur et à mesure du téléchargement du fichier. Notez que cela télécharge un fichier de 100 Mo, ce qui peut prendre un certain temps en fonction de la vitesse de votre connexion.

Pour annuler le téléchargement, vous pouvez appuyer sur Ctrl+C.

Travailler avec les en-têtes de réponse et les métadonnées

Lors du téléchargement de fichiers, les en-têtes de réponse contiennent souvent des métadonnées utiles. Créons un script qui examine les en-têtes de réponse en détail. Créez un fichier appelé response_headers.py :

import requests

def check_url(url):
    print(f"\nChecking URL: {url}")

    try:
        ## Make a HEAD request first to get headers without downloading the full content
        head_response = requests.head(url)

        print(f"HEAD request status code: {head_response.status_code}")

        if head_response.status_code == 200:
            ## Print all headers
            print("\nResponse headers:")
            for header, value in head_response.headers.items():
                print(f"  {header}: {value}")

            ## Extract content type and size
            content_type = head_response.headers.get('Content-Type', 'Unknown')
            content_length = head_response.headers.get('Content-Length', 'Unknown')

            print(f"\nContent Type: {content_type}")

            if content_length != 'Unknown':
                size_kb = int(content_length) / 1024
                size_mb = size_kb / 1024

                if size_mb >= 1:
                    print(f"Content Size: {size_mb:.2f} MB")
                else:
                    print(f"Content Size: {size_kb:.2f} KB")
            else:
                print("Content Size: Unknown")

            ## Check if the server supports range requests
            accept_ranges = head_response.headers.get('Accept-Ranges', 'none')
            print(f"Supports range requests: {'Yes' if accept_ranges != 'none' else 'No'}")

        else:
            print(f"HEAD request failed with status code: {head_response.status_code}")

    except requests.exceptions.RequestException as e:
        print(f"Error: {e}")

## Check a few different URLs
check_url("https://httpbin.org/image/jpeg")
check_url("https://speed.hetzner.de/100MB.bin")
check_url("https://example.com")

Exécutez ce script pour voir des informations détaillées sur les en-têtes de réponse :

python response_headers.py

Vous verrez une sortie affichant les en-têtes pour différents types de contenu, y compris les images, les fichiers binaires et les pages HTML.

Comprendre les en-têtes de réponse est crucial pour de nombreuses tâches de développement web, telles que :

  • Déterminer les types et les tailles de fichiers avant le téléchargement
  • Mettre en œuvre des téléchargements reprenables avec des requêtes de plage (range requests)
  • Vérifier les politiques de mise en cache et les dates d'expiration
  • Gérer les redirections et l'authentification

Résumé

Dans ce lab, vous avez appris à utiliser la bibliothèque Python requests pour interagir avec les services web et les API. Vous avez maintenant les compétences pour :

  1. Effectuer des requêtes HTTP et gérer les codes d'état et les erreurs des réponses
  2. Analyser les données JSON à partir des réponses d'API
  3. Extraire des informations du contenu HTML en utilisant BeautifulSoup
  4. Télécharger et traiter du contenu binaire comme des images et des fichiers
  5. Travailler avec les en-têtes de réponse et les métadonnées

Ces compétences constituent la base de nombreuses applications Python, notamment le web scraping, l'intégration d'API, la collecte de données et l'automatisation. Vous pouvez désormais créer des applications qui interagissent avec les services web, extraire des informations utiles des sites web et traiter divers types de contenu web.

Pour continuer à apprendre, vous pourriez explorer :

  • Les méthodes d'authentification pour accéder aux API protégées
  • Travailler avec des API plus complexes qui nécessitent des en-têtes ou des formats de requête spécifiques
  • Construire un projet complet de web scraping qui collecte et analyse des données
  • Créer une application Python qui s'intègre à plusieurs API

N'oubliez pas que lorsque vous faites du web scraping ou que vous utilisez des API, il est important de vérifier les conditions d'utilisation et de respecter les limites de débit (rate limits) pour éviter d'être bloqué.