# # prompt: schreibe python code um die html webseiten https://www.buergergeld.org/forum/board/63-anspruch-und-leistungen/?pageNo=1 https://www.buergergeld.org/forum/board/63-anspruch-und-leistungen/?pageNo=2 https://www.buergergeld.org/forum/board/63-anspruch-und-leistungen/?pageNo=3 bis https://www.buergergeld.org/forum/board/63-anspruch-und-leistungen/?pageNo=95 herunterzuladen und in einem ordner zu speichern
# import requests
# import os
# def download_pages(base_url, start_page, end_page, output_dir):
# """Downloads HTML pages from a given URL range and saves them to a directory.
# Args:
# base_url: The base URL of the pages to download.
# start_page: The starting page number.
# end_page: The ending page number.
# output_dir: The directory to save the downloaded pages.
# """
# if not os.path.exists(output_dir):
# os.makedirs(output_dir)
# for page_number in range(start_page, end_page + 1):
# url = f"{base_url}?pageNo={page_number}"
# try:
# response = requests.get(url)
# response.raise_for_status() # Raise an exception for bad status codes
# filename = os.path.join(output_dir, f"page_{page_number}.html")
# with open(filename, "w", encoding="utf-8") as file:
# file.write(response.text)
# print(f"Downloaded page {page_number} to {filename}")
# except requests.exceptions.RequestException as e:
# print(f"Error downloading page {page_number}: {e}")
# # Example usage
# base_url = "https://www.buergergeld.org/forum/board/63-anspruch-und-leistungen/"
# start_page = 1
# end_page = 95
# output_directory = "buergergeld_forum"
# download_pages(base_url, start_page, end_page, output_directory)Web Scraping von Foren: Bürgergeld Forum
Web Scraping von Foren
- Herunterladen und Speichern von HTML-Seiten eines Forums.
- Extraktion und Analyse von Forenbeiträgen und Metadaten.
- Verarbeitung und Bereinigung der extrahierten Daten mit Pandas.
HTML-Seiten herunterladen
Dieser Code lädt HTML-Seiten des Bürgergeld Forums herunter und speichert sie in einem Ordner.
Um das wiederholte Abfragen gleicher Inhalte zu vermeiden, können die gesammelten Seiten als Ordner heruntergeladen werden: buergergeld_forum.zip
# prompt: lade die datei von https://www.google.com/url?q=https%3A%2F%2Fhuggingface.co%2Fspaces%2Fdatenwerkzeuge%2FCDL-Webscraping-Workshop-2025%2Fresolve%2Fmain%2Fsrc%2Fassets%2Fbuergergeld_forum.zip und entpacke sie im wurzel ordner "buergergeld_forum"
import requests
import os
from io import BytesIO
from zipfile import ZipFile
# Download the zip file
url = "https://huggingface.co/spaces/datenwerkzeuge/CDL-Webscraping-Workshop-2025/resolve/main/src/assets/buergergeld_forum.zip"
response = requests.get(url)
response.raise_for_status() # Raise an exception for bad status codes
# Extract the zip file
with ZipFile(BytesIO(response.content)) as zip_file:
zip_file.extractall("buergergeld_forum")
print("File downloaded and extracted successfully!")Daten extrahieren
Dieser Code extrahiert die Texte der Elemente <li class="columnSubject">, <li class="columnStats"> und <li class="columnLastPost"> aus den HTML-Dateien und speichert sie in einem Pandas DataFrame.
# prompt: bitte loope über alle html dateien im ordner buergergeld_forum und extrahiere die texte der elemente <li class="columnSubject"> <li class="columnStats"> und <li class="columnLastPost"> und speichere sie in einem pandas dataframe
import pandas as pd
import os
from bs4 import BeautifulSoup
def extract_data(directory):
data = []
for filename in os.listdir(directory):
if filename.endswith(".html"):
filepath = os.path.join(directory, filename)
with open(filepath, "r", encoding="utf-8") as file:
html_content = file.read()
soup = BeautifulSoup(html_content, "html.parser")
# Find all relevant elements on the page
for subject, stats, last_post in zip(soup.find_all("li", class_="columnSubject"),
soup.find_all("li", class_="columnStats"),
soup.find_all("li", class_="columnLastPost")):
#Extract text from each element, handle potential missing elements gracefully
subject_text = subject.text.strip() if subject else ""
stats_text = stats.text.strip() if stats else ""
last_post_text = last_post.text.strip() if last_post else ""
data.append([subject_text, stats_text, last_post_text])
return pd.DataFrame(data, columns=["Subject", "Stats", "LastPost"])
# Example usage
directory = "buergergeld_forum"
df = extract_data(directory)
dfDaten reinigen
Spalte ‘LastPost’ aufteilen
Dieser Code teilt die Spalte df.LastPost in Nutzer_LastPost und Datum_LastPost auf.
# prompt: bitte separariere die spalte df.lastpost in nutzername last post und datum last post indem die spalte an der stelle " \n" getrennt wird
import pandas as pd
# Assuming df is your DataFrame and it has a column named 'LastPost'
# Split the 'LastPost' column at the newline character '\n'
df[['User_LastPost', 'Date_LastPost']] = df['LastPost'].str.split('\n', n=1, expand=True)
# Display the updated DataFrame
dfSpalte ‘Stats’ aufteilen
Dieser Code teilt die Spalte df.Stats in Antworten und Zugriffe auf.
# prompt: bitte teile die spalte df.Stats in zwei spalten an der stelle des ersten vorkommens von "\n\n\n". nenne die erste neue spalte Antworten und die zweite neue Spalte Zugriffe
# Split the 'Stats' column at the first occurrence of "\n\n\n"
df[['Antworten', 'Zugriffe']] = df['Stats'].str.split('\n\n\n', n=1, expand=True)
# Display the updated DataFrame
dfSpalte ‘Zugriffe’ bereinigen
Dieser Code bereinigt die Spalte df.Zugriffe, indem nur der Inhalt bis zum ersten Vorkommen von \n\n\n behalten wird.
# prompt: reinige die spalte df.Zugriffe indem nur der inhalt bis zum ersten vorkommen von "\n\n\n" behalten wird
# Clean the 'Zugriffe' column by keeping only the content up to the first occurrence of "\n\n\n"
df['Zugriffe'] = df['Zugriffe'].str.split('\n\n\n', n=1).str[0]Spalten ‘Antworten’ und ‘Zugriffe’ weiter aufteilen
Dieser Code teilt die Spalten df.Antworten und df.Zugriffe jeweils an der Stelle \n und behält jeweils den zweiten Teil.
# prompt: für die spalten df.Antworten und df.Zugriffe splitte jeweils an der Stelle "\n" und behalte jeweils die zweiten part
# Split the 'Antworten' column at the newline character '\n' and keep the second part
df['Antworten'] = df['Antworten'].str.split('\n').str[1]
# Split the 'Zugriffe' column at the newline character '\n' and keep the second part
df['Zugriffe'] = df['Zugriffe'].str.split('\n').str[1]Spalte ‘Subject’ aufteilen
Dieser Code teilt die Spalte df.Subject am ersten Vorkommen von \n in zwei separate Spalten.
# prompt: in der spalte df.Subject trenne am ersten vorkommen von "\n" in zwei separate spalten
# Split the 'Subject' column at the first occurrence of "\n"
df[['Subject_Part1', 'Subject_Part2']] = df['Subject'].str.split('\n', n=1, expand=True)# prompt: trenne die spalte df.Subject_Part2 an der stelle "\n\n\n\n\n\n\n\n\n\n\n\n" in zwei separate spalten
# Split the 'Subject_Part2' column at the specified string
df[['Subject_Part2_1', 'Subject_Part2_2']] = df['Subject_Part2'].str.split('\n\n\n\n\n\n\n\n\n\n\n\n', n=1, expand=True)# prompt: trenne die spalte df.Subject_Part2_2 in zwei separate spalten an der stelle "\n\n\n"
# Split the 'Subject_Part2_2' column at the specified string
df[['Subject_Part2_2_1', 'Subject_Part2_2_2']] = df['Subject_Part2_2'].str.split('\n\n\n', n=1, expand=True)# prompt: trenne die beiden spalten df.Subject_Part2_2_1 und df.Subject_Part2_2_2 jeweils an der stelle "\n" in separate spalten
# Split the 'Subject_Part2_2_1' and 'Subject_Part2_2_2' columns at the newline character '\n'
df[['Subject_Part2_2_1_split', 'Subject_Part2_2_1_rest']] = df['Subject_Part2_2_1'].str.split('\n', n=1, expand=True)
df[['Subject_Part2_2_2_split', 'Subject_Part2_2_2_rest']] = df['Subject_Part2_2_2'].str.split('\n', n=1, expand=True)Unnötige Spalten entfernen
Dieser Code entfernt die Spalten Stats, LastPost, Subject_Part2, Subject_Part2_2, Subject_Part2_2_1, Subject und Subject_Part2_2_2 aus dem DataFrame df.
# prompt: entferne die spalten Stats, LastPost, Subject_Part2, Subject_Part2_2, Subject_Part2_2_1, Subject und Subject_Part2_2_2 aus dataframe df
df = df.drop(columns=['Stats', 'LastPost', 'Subject_Part2', 'Subject_Part2_2', 'Subject_Part2_2_1', 'Subject', 'Subject_Part2_2_2'])Spalteninhalte vergleichen
Dieser Code vergleicht die Inhalte der Spalten Antworten und Subject_Part2_1.
# prompt: hat die spalte Antworten den gleichen inhalt wie die spalte Subject_Part2_1 ?
# Check if the 'Antworten' column has the same content as the 'Subject_Part2_1' column
comparison_result = df['Antworten'].equals(df['Subject_Part2_1'])
print(f"Do the 'Antworten' and 'Subject_Part2_1' columns have the same content?: {comparison_result}")Weitere Spalteninhalte vergleichen
Dieser Code vergleicht die Inhalte der Spalten User_LastPost und Subject_Part2_2_2_split sowie Date_LastPost und Subject_Part2_2_2_rest.
# prompt: haben die spalten user_lastpost und date_lastpost die gleichen inhalte wie Subject_Part2_2_2_split und Subject_Part2_2_2_rest
# Check if 'user_lastpost' and 'date_lastpost' have the same content as 'Subject_Part2_2_2_split' and 'Subject_Part2_2_2_rest' respectively
comparison_result_user = df['User_LastPost'].equals(df['Subject_Part2_2_2_split'])
comparison_result_date = df['Date_LastPost'].equals(df['Subject_Part2_2_2_rest'])
print(f"Do the 'User_LastPost' and 'Subject_Part2_2_2_split' columns have the same content?: {comparison_result_user}")
print(f"Do the 'Date_LastPost' and 'Subject_Part2_2_2_rest' columns have the same content?: {comparison_result_date}")Spalten umbenennen
Dieser Code benennt die Spalten im DataFrame df um.
# prompt: bitte nenne folgende spalten um im dataframe df : Subject_Part1 in "Thema", User_LastPost in "Nutzer_Letzter_Post", Date_LastPost in "Datum_Letzter_Post", Subject_Part2_1 in "Antworten2", Subject_Part2_2_1_split in "Nutzer", Subject_Part2_2_1_rest in "Datum2", Subject_Part2_2_2_split in "Nutzer3", Subject_Part2_2_2_rest in "Datum3"
df = df.rename(columns={
'Subject_Part1': 'Thema',
'User_LastPost': 'Nutzer_Letzter_Post',
'Date_LastPost': 'Datum_Letzter_Post',
'Subject_Part2_1': 'Antworten2',
'Subject_Part2_2_1_split': 'Nutzer2',
'Subject_Part2_2_1_rest': 'Datum2',
'Subject_Part2_2_2_split': 'Nutzer3',
'Subject_Part2_2_2_rest': 'Datum3'
})Spaltenreihenfolge ändern
Dieser Code ändert die Reihenfolge der Spalten im DataFrame df.
# prompt: bitte ändere die reihenfolge der spalten folgendermaßen: Thema, Nutzer_Letzter_Post, Datum_Letzter_Post, Antworten, Zugriffe, und dann die restlichen spalten
# Define the desired column order
new_column_order = ['Thema', 'Nutzer_Letzter_Post', 'Datum_Letzter_Post', 'Antworten', 'Zugriffe']
# Get the remaining columns not in the new order
remaining_columns = [col for col in df.columns if col not in new_column_order]
# Combine the new column order with the remaining columns
final_column_order = new_column_order + remaining_columns
# Reorder the DataFrame columns
df = df[final_column_order]Spalte ‘Zugriffe’ formatieren
Dieser Code formatiert die Spalte df.Zugriffe als ganze Zahl.
# prompt: bitte formatiere die spalte df.Zugriffe von als ganze zahl, beachte die schreibweise mit , als tausendertrenner und k als abkürzung für tausend
import pandas as pd
# Assuming df is your DataFrame and 'Zugriffe' column needs formatting
# Replace 'k' with '000' and remove ','
df['Zugriffe'] = df['Zugriffe'].str.replace('k', '000', regex=False).str.replace('.', '', regex=False).str.replace(',', '', regex=False)
# Convert the column to integers, handling potential errors
df['Zugriffe'] = pd.to_numeric(df['Zugriffe'], errors='coerce').fillna(0).astype(int)Spalten ‘Antworten’ und ‘Antworten2’ formatieren
Dieser Code formatiert die Spalten df.Antworten und df.Antworten2 als ganze Zahl.
# prompt: bitte ändere die spalte df.Antworten df.Antworten2 in ganze zahl
# Convert 'Antworten' column to integers, handling errors
df['Antworten2'] = pd.to_numeric(df['Antworten2'], errors='coerce').fillna(0).astype(int)Jahr aus ‘Datum_Letzter_Post’ extrahieren
Dieser Code extrahiert Jahreszahlen aus der Spalte df.Datum_Letzter_Post und speichert sie in der Spalte Jahr_Letzter_Post.
# prompt: extrahiere zahlen mit jahresformat in der spalte df.Datum_Letzter_Post und speichere sie in der Spalte "Jahr_Letzter_Post" und setzt die neue spalte als datentyp ganze zahl
import pandas as pd
# Assuming df is your DataFrame and 'Datum_Letzter_Post' column contains dates
# Extract the year from the 'Datum_Letzter_Post' column and store it in 'Jahr_Letzter_Post'
df['Jahr_Letzter_Post'] = df['Datum_Letzter_Post'].str.extract(r'(\d{4})')
# Convert the 'Jahr_Letzter_Post' column to integers
df['Jahr_Letzter_Post'] = pd.to_numeric(df['Jahr_Letzter_Post'], errors='coerce').astype('Int64')DataFrame-Informationen anzeigen
Dieser Code zeigt Informationen über den DataFrame df an.
df.info()Transponierte Daten anzeigen
Dieser Code zeigt die transponierten Daten des DataFrame df an.
df.T[0]Analyse
Dieser Abschnitt enthält die Analyse der Daten.
Wordcloud der Themen
Dieser Code zeigt die Themen mit den meisten Zugriffen als Wordcloud und entfernt zuvor deutsche Stopwörter.
# prompt: zeige die themen mit den meisten zugriffen als wordcloud und entferne deutsche stopwörter zuvor
from wordcloud import WordCloud, STOPWORDS
import matplotlib.pyplot as plt
# Add German stopwords to the default set
german_stopwords = ["und", "der", "die", "das", "in", "den", "zu", "von", "mit", "sich", "des", "eine", "dem", "als", "ist", "für", "auf", "nicht", "auch", "so", "ein", "es", "im", "am", "zum", "über", "er", "sie", "an", "einem", "einer", "werden", "da", "dass", "was", "aber", "wenn", "wie", "wir", "noch", "hat", "man", "hier", "bei", "oder", "nur", "mehr", "nun", "durch", "wieder", "gibt", "wird", "einem", "seine", "ihre", "ihren", "ihrem", "eines", "alles", "einige", "anderer", "anderen", "andere", "dieses", "unser", "euer", "deren"]
stopwords = set(STOPWORDS).union(german_stopwords)
# Assuming 'df' is your DataFrame and 'Thema' is the column with topics
text = " ".join(str(topic) for topic in df['Thema'])
# Generate the word cloud
wordcloud = WordCloud(width=800, height=400, background_color="white", stopwords=stopwords).generate(text)
# Display the word cloud
plt.figure(figsize=(10, 5))
plt.imshow(wordcloud, interpolation="bilinear")
plt.axis("off")
plt.show()Lineplot der Jahreszahlen
Dieser Code zeigt die Spalte df.Jahr_Letzter_Post als Lineplot und stellt sicher, dass die x-Achse ganze Jahreszahlen zeigt.
# prompt: zeige die spalte df.Jahr_Letzter_Post lineplot. beachte dass die x achse als ganze jahreszahlen zeigt
import matplotlib.pyplot as plt
# Assuming df is your DataFrame and 'Jahr_Letzter_Post' is the column with years
# Create the line plot
plt.figure(figsize=(10, 6)) # Adjust figure size as needed
df['Jahr_Letzter_Post'].value_counts().sort_index().plot(kind='line', marker='o')
# Customize the plot
plt.xlabel("Jahr")
plt.ylabel("Anzahl der Posts")
plt.title("Anzahl der Posts pro Jahr")
plt.xticks(rotation=45, ha='right') # Rotate x-axis labels for better readability
plt.grid(True) # Add grid for better visualization
# Show the plot
plt.tight_layout() # Adjust layout to prevent labels from overlapping
plt.show()Themen mit den geringsten Jahreszahlen
Dieser Code zeigt die Themen und die Jahreszahl sowie Datum_Letzter_Post für die 10 Zeilen mit den geringsten Werten bei df.Jahr_Letzter_Post.
# prompt: für 10 zeilen mit den geringsten werten bei df.Jahr_Letzter_Post zeige die Themen und die Jahreszahl und Datum_Letzter_Post
# Display the 10 rows with the lowest values in 'Jahr_Letzter_Post'
# along with the 'Thema' and 'Datum_Letzter_Post' columns.
# Sort by 'Jahr_Letzter_Post' in ascending order and then display the first 10 rows
df_lowest_years = df.sort_values(by='Jahr_Letzter_Post', ascending=True).head(10)
# Select the desired columns
result = df_lowest_years[['Thema', 'Jahr_Letzter_Post', 'Datum_Letzter_Post']]
resultThemen mit den höchsten Jahreszahlen
Dieser Code zeigt die Themen und die Jahreszahl sowie Datum_Letzter_Post für die 10 Zeilen mit den höchsten Werten bei df.Jahr_Letzter_Post.
# prompt: für 10 zeilen mit den höchsten werten bei df.Jahr_Letzter_Post zeige die Themen und die Jahreszahl und Datum_Letzter_Post
# Display the 10 rows with the highest values in 'Jahr_Letzter_Post'
# along with the 'Thema' and 'Datum_Letzter_Post' columns.
# Sort by 'Jahr_Letzter_Post' in descending order and then display the first 10 rows
df_highest_years = df.sort_values(by='Jahr_Letzter_Post', ascending=False).head(10)
# Select the desired columns
result = df_highest_years[['Thema', 'Jahr_Letzter_Post', 'Datum_Letzter_Post']]
resultSpeichern
Dieser Abschnitt enthält den Code zum Speichern der Daten.
Ordner komprimieren
Dieser Code komprimiert den Ordner /content/buergergeld_forum.
# # prompt: bitte kompriere den ordner /content/buergergeld_forum
# import zipfile
# import os
# def compress_directory(directory_path, output_filename):
# """Compresses a directory into a zip file.
# Args:
# directory_path: The path to the directory to compress.
# output_filename: The name of the output zip file.
# """
# try:
# with zipfile.ZipFile(output_filename, 'w', zipfile.ZIP_DEFLATED) as zipf:
# for root, _, files in os.walk(directory_path):
# for file in files:
# file_path = os.path.join(root, file)
# arcname = os.path.relpath(file_path, directory_path)
# zipf.write(file_path, arcname)
# print(f"Successfully compressed '{directory_path}' to '{output_filename}'")
# except FileNotFoundError:
# print(f"Error: Directory '{directory_path}' not found.")
# except Exception as e:
# print(f"An error occurred: {e}")
# # Example usage:
# directory_to_compress = "/content/buergergeld_forum"
# output_zip_filename = "/content/buergergeld_forum.zip" # Specify the desired output filename
# compress_directory(directory_to_compress, output_zip_filename)Fazit
In diesem Notebook haben wir die grundlegenden Techniken des Web Scraping anhand des Bürgergeld Forums erlernt und angewendet. Die wichtigsten gelernten Inhalte umfassen:
- HTML-Seiten herunterladen:
- Wir haben gelernt, wie man HTML-Seiten eines Forums herunterlädt und in einem Ordner speichert.
- Daten extrahieren:
- Wir haben die Texte der relevanten HTML-Elemente extrahiert und in einem Pandas DataFrame gespeichert.
- Daten bereinigen und verarbeiten:
- Wir haben die extrahierten Daten bereinigt und in verschiedene Spalten aufgeteilt, um sie besser analysieren zu können.
- Daten analysieren:
- Wir haben verschiedene Analysetechniken angewendet, darunter das Erstellen von Wordclouds und Lineplots, um die Daten zu visualisieren und zu interpretieren.
- Daten speichern und komprimieren:
- Wir haben gelernt, wie man die verarbeiteten Daten speichert und den Ordner mit den HTML-Dateien komprimiert.
Diese Schritte haben uns gezeigt, wie man Web Scraping effektiv einsetzen kann, um wertvolle Informationen aus Online-Foren zu extrahieren und zu analysieren.