So parsen Sie Antwortinhalte von einem Python-Requests-Aufruf

PythonBeginner
Jetzt üben

Einführung

Die Python-Bibliothek requests ist ein leistungsstarkes Werkzeug für die Interaktion mit Webdiensten und APIs. In diesem Tutorial lernen Sie, wie Sie HTTP-Anfragen senden und Antwortdaten mit Python parsen. Am Ende dieses Labors werden Sie in der Lage sein, wertvolle Informationen aus verschiedenen Arten von API-Antworten zu extrahieren, wodurch Sie datengesteuerte Anwendungen erstellen und Webinteraktionen automatisieren können.

Installation der Requests-Bibliothek und Erstellen einer einfachen Anfrage

In diesem ersten Schritt installieren wir die Python-Bibliothek requests und erstellen unsere erste HTTP-Anfrage, um Daten von einer öffentlichen API abzurufen.

Installieren von Requests

Die requests-Bibliothek ist ein Drittanbieter-Paket, das mit pip, dem Paketinstallationsprogramm von Python, installiert werden muss. Beginnen wir mit der Installation:

pip install requests

Sie sollten eine Ausgabe sehen, die bestätigt, dass requests erfolgreich installiert wurde.

Erstellen Ihrer ersten HTTP-Anfrage

Erstellen wir nun eine Python-Datei, um eine einfache HTTP-Anfrage zu erstellen. Erstellen Sie in der WebIDE eine neue Datei namens basic_request.py im Verzeichnis /home/labex/project.

Fügen Sie der Datei den folgenden Code hinzu:

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}")

Dieser Code sendet eine GET-Anfrage an einen Beispiel-API-Endpunkt und gibt Informationen über die Antwort aus.

Verstehen des Response-Objekts

Lassen Sie uns den Code ausführen, um zu sehen, welche Informationen wir zurückbekommen. Führen Sie im Terminal Folgendes aus:

python basic_request.py

Sie sollten eine Ausgabe ähnlich dieser sehen:

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
...

Das Response-Objekt enthält mehrere wichtige Attribute:

  • status_code: HTTP-Statuscode (200 bedeutet Erfolg)
  • text: Der Antwortinhalt als Zeichenkette (String)
  • headers: Ein Dictionary der Antwort-Header

Bei der Arbeit mit Webanfragen helfen Ihnen diese Attribute, die Antwort des Servers zu verstehen und entsprechend zu behandeln.

HTTP-Statuscodes

HTTP-Statuscodes geben an, ob eine Anfrage erfolgreich war oder fehlgeschlagen ist:

  • 2xx (wie 200): Erfolg
  • 3xx (wie 301): Weiterleitung (Redirection)
  • 4xx (wie 404): Client-Fehler
  • 5xx (wie 500): Server-Fehler

Ändern wir unseren Code, um auf eine erfolgreiche Antwort zu prüfen. Erstellen Sie eine neue Datei namens check_status.py mit diesem Inhalt:

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}")

Führen Sie diesen Code aus, um zu sehen, wie verschiedene URLs unterschiedliche Statuscodes zurückgeben:

python check_status.py

Sie sollten sehen, dass die gültige URL den Statuscode 200 zurückgibt, während die ungültige URL den Statuscode 404 zurückgibt.

Parsen von JSON-Antwortdaten

Viele moderne APIs geben Daten im JSON-Format (JavaScript Object Notation) zurück. In diesem Schritt lernen Sie, wie Sie JSON-Antworten parsen und mit den Daten in Python arbeiten.

Verstehen von JSON

JSON ist ein leichtgewichtiges Datenaustauschformat, das für Menschen leicht zu lesen und zu schreiben ist und für Maschinen leicht zu parsen und zu generieren ist. Es basiert auf Schlüssel-Wert-Paaren, ähnlich wie Python-Dictionaries.

Hier ist ein Beispiel für ein JSON-Objekt:

{
  "name": "John Doe",
  "age": 30,
  "email": "john@example.com",
  "is_active": true,
  "hobbies": ["reading", "swimming", "cycling"]
}

Parsen von JSON-Antworten

Die requests-Bibliothek vereinfacht das Parsen von JSON-Antworten mit der Methode .json(). Erstellen wir eine neue Datei namens parse_json.py und fügen Sie den folgenden Code hinzu:

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}")

Führen Sie dieses Skript aus, um zu sehen, wie die JSON-Daten in ein Python-Dictionary geparst werden:

python parse_json.py

Sie sollten eine Ausgabe sehen, die Informationen über den GitHub-Benutzer anzeigt, einschließlich seines Benutzernamens, der Anzahl der Follower und der Anzahl der Repositorys.

Arbeiten mit Datenlisten

Viele APIs geben Listen von Objekten zurück. Sehen wir uns an, wie man diese Art von Antwort behandelt. Erstellen Sie eine Datei namens json_list.py mit diesem Inhalt:

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}")

Führen Sie dieses Skript aus, um zu sehen, wie eine Liste von JSON-Objekten verarbeitet wird:

python json_list.py

Sie sollten Informationen über die ersten drei Beiträge sehen, einschließlich ihrer Titel und des Beginns ihres Inhalts.

Fehlerbehandlung beim JSON-Parsen

Manchmal enthält eine Antwort möglicherweise keine gültigen JSON-Daten. Sehen wir uns an, wie man dies elegant handhabt. Erstellen Sie eine Datei namens json_error.py mit diesem 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")

Führen Sie dieses Skript aus, um zu sehen, wie verschiedene Arten von Antworten behandelt werden:

python json_error.py

Sie sollten sehen, dass der Code sowohl gültige JSON-Antworten als auch Nicht-JSON-Antworten erfolgreich verarbeitet.

Parsen von HTML-Inhalten mit BeautifulSoup

Bei der Arbeit mit Webdaten werden Sie oft auf HTML-Antworten stoßen. Für das Parsen von HTML ist die Python-Bibliothek BeautifulSoup ein hervorragendes Werkzeug. In diesem Schritt lernen wir, wie man Informationen aus HTML-Antworten extrahiert.

Installieren von BeautifulSoup

Zuerst installieren wir BeautifulSoup und seinen HTML-Parser:

pip install beautifulsoup4

Grundlegendes HTML-Parsen

Erstellen wir eine Datei namens parse_html.py, um eine Webseite abzurufen und zu parsen:

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}")

Führen Sie dieses Skript aus, um zu sehen, wie man grundlegende Informationen von einer HTML-Seite extrahiert:

python parse_html.py

Sie sollten eine Ausgabe sehen, die den Seitentitel, die Anzahl der Absätze, den Text des ersten Absatzes, die Anzahl der Links und die URL des ersten Links anzeigt.

Finden bestimmter Elemente

Sehen wir uns nun an, wie man bestimmte Elemente mit CSS-Selektoren findet. Erstellen Sie eine Datei namens 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}")

Führen Sie dieses Skript aus, um zu sehen, wie man CSS-Selektoren verwendet, um bestimmte Elemente zu extrahieren:

python html_selectors.py

Sie sollten eine Ausgabe sehen, die Informationen über die ersten drei Zitate anzeigt, einschließlich des Zitattests, des Autors und der Tags.

Erstellen eines einfachen Web Scrapers

Lassen Sie uns alles zusammenfügen, um einen einfachen Web-Scraper zu erstellen, der strukturierte Daten von einer Webseite extrahiert. Erstellen Sie eine Datei namens 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")

Führen Sie dieses Skript aus, um Zitate von einer Website zu scrapen:

python quotes_scraper.py

Sie sollten eine Ausgabe sehen, die Informationen über die auf der ersten Seite gefundenen Zitate anzeigt, und die Zitate werden in einer JSON-Datei namens quotes.json gespeichert.

Überprüfen Sie die JSON-Datei, um die strukturierten Daten zu sehen:

cat quotes.json

Die Datei sollte ein JSON-Array von Zitatobjekten enthalten, jedes mit den Eigenschaften Text, Autor und Tags.

Arbeiten mit binären Antwortinhalten

Bisher haben wir uns auf textbasierte Antworten wie JSON und HTML konzentriert. Die requests-Bibliothek kann jedoch auch binäre Inhalte wie Bilder, PDFs und andere Dateien verarbeiten. In diesem Schritt lernen wir, wie man binäre Inhalte herunterlädt und verarbeitet.

Herunterladen eines Bildes

Beginnen wir mit dem Herunterladen eines Bildes. Erstellen Sie eine Datei namens 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}")

Führen Sie dieses Skript aus, um ein Bild herunterzuladen:

python download_image.py

Sie sollten eine Ausgabe sehen, die bestätigt, dass das Bild heruntergeladen und in /home/labex/project/downloads/sample_image.jpg gespeichert wurde.

Herunterladen einer Datei mit Fortschrittsanzeige

Beim Herunterladen großer Dateien kann es nützlich sein, eine Fortschrittsanzeige anzuzeigen. Erstellen wir ein Skript, das den Download-Fortschritt anzeigt. Erstellen Sie eine Datei namens 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.")

Führen Sie dieses Skript aus, um eine Datei mit Fortschrittsanzeige herunterzuladen:

python download_with_progress.py

Sie sehen eine Fortschrittsanzeige, die sich während des Downloads der Datei aktualisiert. Beachten Sie, dass dies eine 100MB-Datei herunterlädt, was je nach Ihrer Verbindungsgeschwindigkeit einige Zeit dauern kann.

Um den Download abzubrechen, können Sie Strg+C drücken.

Arbeiten mit Antwort-Headern und Metadaten

Beim Herunterladen von Dateien enthalten die Antwort-Header oft nützliche Metadaten. Erstellen wir ein Skript, das Antwort-Header im Detail untersucht. Erstellen Sie eine Datei namens 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")

Führen Sie dieses Skript aus, um detaillierte Informationen zu Antwort-Headern anzuzeigen:

python response_headers.py

Sie sehen eine Ausgabe, die die Header für verschiedene Arten von Inhalten anzeigt, einschließlich Bilder, Binärdateien und HTML-Seiten.

Das Verständnis von Antwort-Headern ist für viele Webentwicklungsaufgaben von entscheidender Bedeutung, wie z.B.:

  • Bestimmen von Dateitypen und -größen vor dem Herunterladen
  • Implementieren von fortsetzbaren Downloads mit Bereichsanforderungen (range requests)
  • Überprüfen von Caching-Richtlinien und Ablaufdaten
  • Umgang mit Weiterleitungen und Authentifizierung

Zusammenfassung

In diesem Lab haben Sie gelernt, wie Sie mit der Python-requests-Bibliothek arbeiten, um mit Webdiensten und APIs zu interagieren. Sie verfügen nun über die Fähigkeiten, um:

  1. HTTP-Anfragen zu stellen und Antwortstatuscodes und -fehler zu behandeln
  2. JSON-Daten aus API-Antworten zu parsen
  3. Informationen aus HTML-Inhalten mit BeautifulSoup zu extrahieren
  4. Binäre Inhalte wie Bilder und Dateien herunterzuladen und zu verarbeiten
  5. Mit Antwort-Headern und Metadaten zu arbeiten

Diese Fähigkeiten bilden die Grundlage für viele Python-Anwendungen, einschließlich Web Scraping, API-Integration, Datenerfassung und Automatisierung. Sie können jetzt Anwendungen erstellen, die mit Webdiensten interagieren, nützliche Informationen von Websites extrahieren und verschiedene Arten von Webinhalten verarbeiten.

Um weiter zu lernen, könnten Sie Folgendes erkunden:

  • Authentifizierungsmethoden für den Zugriff auf geschützte APIs
  • Arbeiten mit komplexeren APIs, die bestimmte Header oder Anfrageformate erfordern
  • Erstellen eines vollständigen Web Scraping-Projekts, das Daten sammelt und analysiert
  • Erstellen einer Python-Anwendung, die sich in mehrere APIs integriert

Denken Sie daran, dass es beim Scraping von Websites oder der Verwendung von APIs wichtig ist, die Nutzungsbedingungen zu überprüfen und Ratenbegrenzungen zu respektieren, um eine Blockierung zu vermeiden.