Skip to content

Kapitel 17: Fortgeschrittene Praxis

🎯 Lernziele

In diesem Kapitel wirst du:

  • Einen einfachen Web-Crawler programmieren
  • Eine GUI-Anwendung mit Tkinter erstellen
  • Datenbankoperationen mit SQLite durchführen
  • Dateien mit os und shutil verwalten

🌐 Praxis 1: Einfacher Web-Crawler

📋 Anforderungsanalyse

Funktionalitäten:

  • ✅ Webseite herunterladen
  • ✅ HTML parsen
  • ✅ Links extrahieren
  • ✅ Bilder herunterladen

💻 Vollständiger Code

python
import requests
from bs4 import BeautifulSoup
import os

def web_crawler(url, ziel_ordner="crawler_output"):
    """Einfacher Web-Crawler"""
    try:
        # Erstelle Zielordner
        os.makedirs(ziel_ordner, exist_ok=True)
        
        # Webseite herunterladen
        print(f"Lade {url}...")
        response = requests.get(url, timeout=10)
        response.raise_for_status()  # Fehler überprüfen
        
        # HTML parsen
        soup = BeautifulSoup(response.text, "html.parser")
        
        # Titel extrahieren
        titel = soup.title.string if soup.title else "Kein Titel"
        print(f"Seitentitel: {titel}")
        
        # Links extrahieren
        links = []
        for link in soup.find_all("a", href=True):
            links.append(link["href"])
        
        print(f"Gefundene Links: {len(links)}")
        
        # Links in Datei speichern
        with open(f"{ziel_ordner}/links.txt", "w", encoding="utf-8") as f:
            for link in links:
                f.write(link + "\n")
        
        # Bilder herunterladen
        bilder = soup.find_all("img", src=True)
        print(f"Gefundene Bilder: {len(bilder)}")
        
        for i, bild in enumerate(bilder[:5]):  # Nur die ersten 5 Bilder
            try:
                bild_url = bild["src"]
                if not bild_url.startswith("http"):
                    continue
                
                bild_response = requests.get(bild_url, timeout=5)
                bild_pfad = f"{ziel_ordner}/bild_{i}.jpg"
                
                with open(bild_pfad, "wb") as f:
                    f.write(bild_response.content)
                
                print(f"Bild {i+1} heruntergeladen: {bild_pfad}")
                
            except Exception as e:
                print(f"Fehler beim Herunterladen von Bild {i+1}: {e}")
        
        print(f"\nCrawling abgeschlossen! Ergebnisse in '{ziel_ordner}'")
        
    except requests.exceptions.RequestException as e:
        print(f"Fehler beim Zugriff auf {url}: {e}")
    except Exception as e:
        print(f"Ein Fehler ist aufgetreten: {e}")

# Hauptprogramm
if __name__ == "__main__":
    url = input("Gib die URL der Webseite ein: ")
    web_crawler(url)

🧪 Testlauf

Gib die URL der Webseite ein: https://example.com
Lade https://example.com...
Seitentitel: Example Domain
Gefundene Links: 1
Gefundene Bilder: 1
Bild 1 heruntergeladen: crawler_output/bild_0.jpg

Crawling abgeschlossen! Ergebnisse in 'crawler_output'

🖥️ Praxis 2: GUI-Entwicklung mit Tkinter

📋 Anforderungsanalyse

Funktionalitäten:

  • ✅ Einfaches Fenster erstellen
  • ✅ Eingabefelder und Buttons hinzufügen
  • ✅ Ereignisse (Events) behandeln
  • ✅ Einfachen Taschenrechner erstellen

💻 Vollständiger Code

python
import tkinter as tk
from tkinter import messagebox

class Taschenrechner:
    def __init__(self, master):
        self.master = master
        master.title("Einfacher Taschenrechner")
        master.geometry("300x200")
        
        # Eingabefelder
        self.label1 = tk.Label(master, text="Zahl 1:")
        self.label1.pack()
        
        self.entry1 = tk.Entry(master)
        self.entry1.pack()
        
        self.label2 = tk.Label(master, text="Zahl 2:")
        self.label2.pack()
        
        self.entry2 = tk.Entry(master)
        self.entry2.pack()
        
        # Buttons
        self.button_frame = tk.Frame(master)
        self.button_frame.pack(pady=10)
        
        self.add_button = tk.Button(self.button_frame, text="+", command=self.addieren)
        self.add_button.pack(side=tk.LEFT, padx=5)
        
        self.sub_button = tk.Button(self.button_frame, text="-", command=self.subtrahieren)
        self.sub_button.pack(side=tk.LEFT, padx=5)
        
        self.mul_button = tk.Button(self.button_frame, text="*", command=self.multiplizieren)
        self.mul_button.pack(side=tk.LEFT, padx=5)
        
        self.div_button = tk.Button(self.button_frame, text="/", command=self.dividieren)
        self.div_button.pack(side=tk.LEFT, padx=5)
        
        # Ergebnis
        self.ergebnis_label = tk.Label(master, text="Ergebnis:")
        self.ergebnis_label.pack(pady=10)
    
    def addieren(self):
        try:
            zahl1 = float(self.entry1.get())
            zahl2 = float(self.entry2.get())
            ergebnis = zahl1 + zahl2
            self.ergebnis_label.config(text=f"Ergebnis: {ergebnis}")
        except ValueError:
            messagebox.showerror("Fehler", "Bitte gib gültige Zahlen ein!")
    
    def subtrahieren(self):
        try:
            zahl1 = float(self.entry1.get())
            zahl2 = float(self.entry2.get())
            ergebnis = zahl1 - zahl2
            self.ergebnis_label.config(text=f"Ergebnis: {ergebnis}")
        except ValueError:
            messagebox.showerror("Fehler", "Bitte gib gültige Zahlen ein!")
    
    def multiplizieren(self):
        try:
            zahl1 = float(self.entry1.get())
            zahl2 = float(self.entry2.get())
            ergebnis = zahl1 * zahl2
            self.ergebnis_label.config(text=f"Ergebnis: {ergebnis}")
        except ValueError:
            messagebox.showerror("Fehler", "Bitte gib gültige Zahlen ein!")
    
    def dividieren(self):
        try:
            zahl1 = float(self.entry1.get())
            zahl2 = float(self.entry2.get())
            if zahl2 == 0:
                messagebox.showerror("Fehler", "Division durch Null ist nicht erlaubt!")
                return
            ergebnis = zahl1 / zahl2
            self.ergebnis_label.config(text=f"Ergebnis: {ergebnis}")
        except ValueError:
            messagebox.showerror("Fehler", "Bitte gib gültige Zahlen ein!")

# Hauptprogramm
if __name__ == "__main__":
    root = tk.Tk()
    app = Taschenrechner(root)
    root.mainloop()

🧪 Testlauf

[GUI-Fenster wird angezeigt]
Zahl 1: 10
Zahl 2: 5

[+] Button klicken → Ergebnis: 15.0
[-] Button klicken → Ergebnis: 5.0
[*] Button klicken → Ergebnis: 50.0
[/] Button klicken → Ergebnis: 2.0

🗄️ Praxis 3: Datenbankoperationen mit SQLite

📋 Anforderungsanalyse

Funktionalitäten:

  • ✅ Datenbank erstellen
  • ✅ Tabellen erstellen
  • ✅ Daten einfügen
  • ✅ Daten abfragen
  • ✅ Daten aktualisieren und löschen

💻 Vollständiger Code

python
import sqlite3
from datetime import datetime

class Datenbank:
    def __init__(self, db_name="beispiel.db"):
        self.db_name = db_name
        self.verbindung = None
        self.cursor = None
    
    def verbinden(self):
        """Stellt eine Verbindung zur Datenbank her"""
        try:
            self.verbindung = sqlite3.connect(self.db_name)
            self.cursor = self.verbindung.cursor()
            print(f"Mit Datenbank '{self.db_name}' verbunden.")
        except sqlite3.Error as e:
            print(f"Fehler beim Verbinden mit der Datenbank: {e}")
    
    def trennen(self):
        """Trennt die Verbindung zur Datenbank"""
        if self.verbindung:
            self.verbindung.close()
            print(f"Verbindung zur Datenbank '{self.db_name}' getrennt.")
    
    def tabelle_erstellen(self):
        """Erstellt die Tabelle 'studenten'"""
        try:
            self.cursor.execute("""
                CREATE TABLE IF NOT EXISTS studenten (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    name TEXT NOT NULL,
                    alter INTEGER,
                    fach TEXT,
                    erstellt_am TIMESTAMP DEFAULT CURRENT_TIMESTAMP
                )
            """)
            self.verbindung.commit()
            print("Tabelle 'studenten' erstellt (oder bereits vorhanden).")
        except sqlite3.Error as e:
            print(f"Fehler beim Erstellen der Tabelle: {e}")
    
    def student_einfügen(self, name, alter, fach):
        """Fügt einen neuen Studenten hinzu"""
        try:
            self.cursor.execute("""
                INSERT INTO studenten (name, alter, fach)
                VALUES (?, ?, ?)
            """, (name, alter, fach))
            self.verbindung.commit()
            print(f"Student '{name}' erfolgreich hinzugefügt.")
            return self.cursor.lastrowid
        except sqlite3.Error as e:
            print(f"Fehler beim Einfügen des Studenten: {e}")
            return None
    
    def student_abfragen(self, student_id=None):
        """Fragt Studenten ab (alle oder nach ID)"""
        try:
            if student_id:
                self.cursor.execute("SELECT * FROM studenten WHERE id = ?", (student_id,))
                student = self.cursor.fetchone()
                if student:
                    print(f"Student gefunden: ID={student[0]}, Name={student[1]}, Alter={student[2]}, Fach={student[3]}, Erstellt am={student[4]}")
                else:
                    print(f"Kein Student mit ID {student_id} gefunden.")
            else:
                self.cursor.execute("SELECT * FROM studenten")
                studenten = self.cursor.fetchall()
                if studenten:
                    print(f"\n=== Alle Studenten ({len(studenten)}) ===")
                    for student in studenten:
                        print(f"  ID={student[0]}, Name={student[1]}, Alter={student[2]}, Fach={student[3]}")
                else:
                    print("Keine Studenten in der Datenbank.")
        except sqlite3.Error as e:
            print(f"Fehler beim Abfragen der Studenten: {e}")
    
    def student_aktualisieren(self, student_id, name=None, alter=None, fach=None):
        """Aktualisiert einen Studenten"""
        try:
            # Überprüfen, ob der Student existiert
            self.cursor.execute("SELECT * FROM studenten WHERE id = ?", (student_id,))
            if not self.cursor.fetchone():
                print(f"Fehler: Kein Student mit ID {student_id} gefunden.")
                return False
            
            # Aktualisierung durchführen
            if name:
                self.cursor.execute("UPDATE studenten SET name = ? WHERE id = ?", (name, student_id))
            if alter:
                self.cursor.execute("UPDATE studenten SET alter = ? WHERE id = ?", (alter, student_id))
            if fach:
                self.cursor.execute("UPDATE studenten SET fach = ? WHERE id = ?", (fach, student_id))
            
            self.verbindung.commit()
            print(f"Student mit ID {student_id} erfolgreich aktualisiert.")
            return True
        except sqlite3.Error as e:
            print(f"Fehler beim Aktualisieren des Studenten: {e}")
            return False
    
    def student_löschen(self, student_id):
        """Löscht einen Studenten"""
        try:
            # Überprüfen, ob der Student existiert
            self.cursor.execute("SELECT * FROM studenten WHERE id = ?", (student_id,))
            if not self.cursor.fetchone():
                print(f"Fehler: Kein Student mit ID {student_id} gefunden.")
                return False
            
            # Löschen durchführen
            self.cursor.execute("DELETE FROM studenten WHERE id = ?", (student_id,))
            self.verbindung.commit()
            print(f"Student mit ID {student_id} erfolgreich gelöscht.")
            return True
        except sqlite3.Error as e:
            print(f"Fehler beim Löschen des Studenten: {e}")
            return False

# Hauptprogramm
if __name__ == "__main__":
    db = Datenbank()
    db.verbinden()
    db.tabelle_erstellen()
    
    # Studenten hinzufügen
    id1 = db.student_einfügen("Max Mustermann", 20, "Informatik")
    id2 = db.student_einfügen("Anna Beispiel", 22, "Mathematik")
    
    # Studenten abfragen
    db.student_abfragen()
    
    # Student aktualisieren
    if id1:
        db.student_aktualisieren(id1, alter=21)
    
    # Student löschen
    if id2:
        db.student_löschen(id2)
    
    # Erneut abfragen
    db.student_abfragen()
    
    db.trennen()

🧪 Testlauf

Mit Datenbank 'beispiel.db' verbunden.
Tabelle 'studenten' erstellt (oder bereits vorhanden).
Student 'Max Mustermann' erfolgreich hinzugefügt.
Student 'Anna Beispiel' erfolgreich hinzugefügt.

=== Alle Studenten (2) ===
  ID=1, Name=Max Mustermann, Alter=20, Fach=Informatik
  ID=2, Name=Anna Beispiel, Alter=22, Fach=Mathematik

Student mit ID 1 erfolgreich aktualisiert.
Student mit ID 2 erfolgreich gelöscht.

=== Alle Studenten (1) ===
  ID=1, Name=Max Mustermann, Alter=21, Fach=Informatik

Verbindung zur Datenbank 'beispiel.db' getrennt.

📂 Praxis 4: Dateiverwaltung mit os und shutil

📋 Anforderungsanalyse

Funktionalitäten:

  • ✅ Dateien und Ordner erstellen
  • ✅ Dateien kopieren und verschieben
  • ✅ Dateien umbenennen und löschen
  • ✅ Dateiinformationen abfragen

💻 Vollständiger Code

python
import os
import shutil
from datetime import datetime

class Dateiverwaltung:
    def __init__(self, basis_pfad="."):
        self.basis_pfad = basis_pfad
    
    def ordner_erstellen(self, ordner_name):
        """Erstellt einen Ordner"""
        try:
            ordner_pfad = os.path.join(self.basis_pfad, ordner_name)
            os.makedirs(ordner_pfad, exist_ok=True)
            print(f"Ordner '{ordner_name}' erstellt.")
            return ordner_pfad
        except OSError as e:
            print(f"Fehler beim Erstellen des Ordners: {e}")
            return None
    
    def datei_erstellen(self, datei_name, inhalt=""):
        """Erstellt eine Datei mit Inhalt"""
        try:
            datei_pfad = os.path.join(self.basis_pfad, datei_name)
            with open(datei_pfad, "w", encoding="utf-8") as f:
                f.write(inhalt)
            print(f"Datei '{datei_name}' erstellt.")
            return datei_pfad
        except IOError as e:
            print(f"Fehler beim Erstellen der Datei: {e}")
            return None
    
    def datei_kopieren(self, quelle, ziel):
        """Kopiert eine Datei"""
        try:
            quell_pfad = os.path.join(self.basis_pfad, quelle)
            ziel_pfad = os.path.join(self.basis_pfad, ziel)
            shutil.copy2(quell_pfad, ziel_pfad)
            print(f"Datei '{quelle}' nach '{ziel}' kopiert.")
            return True
        except IOError as e:
            print(f"Fehler beim Kopieren der Datei: {e}")
            return False
    
    def datei_verschieben(self, quelle, ziel):
        """Verschiebt eine Datei"""
        try:
            quell_pfad = os.path.join(self.basis_pfad, quelle)
            ziel_pfad = os.path.join(self.basis_pfad, ziel)
            shutil.move(quell_pfad, ziel_pfad)
            print(f"Datei '{quelle}' nach '{ziel}' verschoben.")
            return True
        except IOError as e:
            print(f"Fehler beim Verschieben der Datei: {e}")
            return False
    
    def datei_umbenennen(self, alte_name, neue_name):
        """Benennt eine Datei um"""
        try:
            alte_pfad = os.path.join(self.basis_pfad, alte_name)
            neue_pfad = os.path.join(self.basis_pfad, neue_name)
            os.rename(alte_pfad, neue_pfad)
            print(f"Datei '{alte_name}' in '{neue_name}' umbenannt.")
            return True
        except OSError as e:
            print(f"Fehler beim Umbenennen der Datei: {e}")
            return False
    
    def datei_löschen(self, datei_name):
        """Löscht eine Datei"""
        try:
            datei_pfad = os.path.join(self.basis_pfad, datei_name)
            os.remove(datei_pfad)
            print(f"Datei '{datei_name}' gelöscht.")
            return True
        except OSError as e:
            print(f"Fehler beim Löschen der Datei: {e}")
            return False
    
    def ordner_löschen(self, ordner_name, rekursiv=False):
        """Löscht einen Ordner"""
        try:
            ordner_pfad = os.path.join(self.basis_pfad, ordner_name)
            if rekursiv:
                shutil.rmtree(ordner_pfad)
            else:
                os.rmdir(ordner_pfad)
            print(f"Ordner '{ordner_name}' gelöscht.")
            return True
        except OSError as e:
            print(f"Fehler beim Löschen des Ordners: {e}")
            return False
    
    def datei_info(self, datei_name):
        """Zeigt Dateiinformationen an"""
        try:
            datei_pfad = os.path.join(self.basis_pfad, datei_name)
            info = os.stat(datei_pfad)
            print(f"\n=== Dateiinformationen für '{datei_name}' ===")
            print(f"Größe: {info.st_size} Bytes")
            print(f"Erstellt am: {datetime.fromtimestamp(info.st_ctime)}")
            print(f"Zuletzt geändert am: {datetime.fromtimestamp(info.st_mtime)}")
            return info
        except OSError as e:
            print(f"Fehler beim Abrufen der Dateiinformationen: {e}")
            return None
    
    def dateien_auflisten(self, ordner_name=None):
        """Listet alle Dateien in einem Ordner auf"""
        try:
            if ordner_name:
                ordner_pfad = os.path.join(self.basis_pfad, ordner_name)
            else:
                ordner_pfad = self.basis_pfad
            
            dateien = os.listdir(ordner_pfad)
            print(f"\n=== Dateien in '{ordner_pfad}' ===")
            for datei in dateien:
                datei_pfad = os.path.join(ordner_pfad, datei)
                if os.path.isfile(datei_pfad):
                    print(f"  [Datei] {datei}")
                elif os.path.isdir(datei_pfad):
                    print(f"  [Ordner] {datei}")
            return dateien
        except OSError as e:
            print(f"Fehler beim Auflisten der Dateien: {e}")
            return None

# Hauptprogramm
if __name__ == "__main__":
    dv = Dateiverwaltung()
    
    # Ordner erstellen
    dv.ordner_erstellen("test_ordner")
    
    # Dateien erstellen
    dv.datei_erstellen("test1.txt", "Das ist die erste Testdatei.")
    dv.datei_erstellen("test2.txt", "Das ist die zweite Testdatei.")
    dv.datei_erstellen(os.path.join("test_ordner", "test3.txt"), "Das ist die dritte Testdatei im Ordner.")
    
    # Dateien auflisten
    dv.dateien_auflisten()
    dv.dateien_auflisten("test_ordner")
    
    # Datei kopieren
    dv.datei_kopieren("test1.txt", "test1_kopie.txt")
    
    # Datei verschieben
    dv.datei_verschieben("test2.txt", os.path.join("test_ordner", "test2_verschoben.txt"))
    
    # Datei umbenennen
    dv.datei_umbenennen("test1_kopie.txt", "test1_neu.txt")
    
    # Dateiinformationen anzeigen
    dv.datei_info("test1_neu.txt")
    
    # Datei löschen
    dv.datei_löschen("test1_neu.txt")
    
    # Ordner löschen (rekursiv)
    dv.ordner_löschen("test_ordner", rekursiv=True)

🧪 Testlauf

Ordner 'test_ordner' erstellt.
Datei 'test1.txt' erstellt.
Datei 'test2.txt' erstellt.
Datei 'test_ordner/test3.txt' erstellt.

=== Dateien in '.' ===
  [Datei] test1.txt
  [Datei] test2.txt
  [Ordner] test_ordner

=== Dateien in 'test_ordner' ===
  [Datei] test3.txt

Datei 'test1.txt' nach 'test1_kopie.txt' kopiert.
Datei 'test2.txt' nach 'test_ordner/test2_verschoben.txt' verschoben.
Datei 'test1_kopie.txt' in 'test1_neu.txt' umbenannt.

=== Dateiinformationen für 'test1_neu.txt' ===
Größe: 32 Bytes
Erstellt am: 2024-01-15 10:30:00
Zuletzt geändert am: 2024-01-15 10:30:00

Datei 'test1_neu.txt' gelöscht.
Ordner 'test_ordner' gelöscht.

📝 Zusammenfassung

In diesem Kapitel hast du gelernt:

  • ✅ Einen einfachen Web-Crawler zu programmieren
  • ✅ Eine GUI-Anwendung mit Tkinter zu erstellen
  • ✅ Datenbankoperationen mit SQLite durchzuführen
  • ✅ Dateien mit os und shutil zu verwalten

🎯 Übung

  1. Erweitere den Web-Crawler: Füge eine Funktion hinzu, die den Text einer Webseite extrahiert und in einer Datei speichert.
  2. Erweitere die GUI-Anwendung: Füge weitere Funktionen hinzu (z.B. Löschen, zurücksetzen).
  3. Erweitere die Datenbankoperationen: Füge eine Suchfunktion hinzu.
  4. Erweitere die Dateiverwaltung: Füge eine Funktion hinzu, die Dateien nach Endung filtert.

⏭️ Nächstes Kapitel

In Kapitel 18 werden wir Fehlerbehebung und Debugging lernen - wie man Fehler findet und behebt!

Frei für alle Anfänger