- Scraper: HTML-Extraktion von ECOnGOOD-Webseite - Analyzer: LLM-Bewertung (Qwen) nach GWÖ-Matrix 2.0 - Aggregator: Partei-Auswertung + Kandidat:innen-Ranking - CLI: Reproduzierbarer Workflow (scrape → analyze → aggregate) - Output: 7 Dokumente inkl. Pressemitteilung und Methodik - 27 Kandidat:innen, 162 Einzelbewertungen
172 lines
4.9 KiB
Markdown
172 lines
4.9 KiB
Markdown
# Wahlprüfsteine-Auswertung — Technische Dokumentation
|
||
|
||
## Übersicht
|
||
|
||
CLI-Tool zur automatisierten GWÖ-Analyse von Wahlprüfstein-Antworten mit Partei-Aggregation und Kandidat:innen-Ranking.
|
||
|
||
## Komponenten
|
||
|
||
### 1. Scraper (`scraper.py`)
|
||
|
||
**Funktion:** Extrahiert Kandidat:innen und Antworten aus der ECOnGOOD-Webseite.
|
||
|
||
**Ablauf:**
|
||
1. HTML von URL laden (oder lokale Datei)
|
||
2. Tabellen parsen mit BeautifulSoup
|
||
3. Parteinamen normalisieren (Fuzzy-Matching)
|
||
4. In SQLite speichern
|
||
|
||
**Partei-Normalisierung:**
|
||
```python
|
||
PARTEI_MAPPING = {
|
||
r'bündnis\s*90\s*/?\s*die\s*grünen?': 'Grüne',
|
||
r'freie\s*wähler': 'Freie Wähler',
|
||
r'^csu$': 'CSU',
|
||
# ...
|
||
}
|
||
```
|
||
|
||
### 2. Analyzer (`analyzer.py`)
|
||
|
||
**Funktion:** Bewertet jede Antwort mit Qwen LLM nach GWÖ-Kriterien.
|
||
|
||
**Prompt-Struktur:**
|
||
- System: GWÖ-Matrix 2.0 Kontext + Bewertungsskalen
|
||
- User: Frage + Antwort + Kandidat:in-Info
|
||
- Output: Strukturiertes JSON
|
||
|
||
**Bewertungsdimensionen:**
|
||
- `substanz_score` (0-3): Konkretheit der Antwort
|
||
- `umfang`: keine/kurz/mittel/ausführlich
|
||
- `gwoe_score` (0-10): Übereinstimmung mit Matrix
|
||
- `matrix_felder`: Berührte GWÖ-Felder (z.B. ["D5", "C2"])
|
||
- `staerken/schwaechen`: Qualitative Analyse
|
||
|
||
**API-Konfiguration:**
|
||
```python
|
||
client = OpenAI(
|
||
api_key=keychain["qwen-api"],
|
||
base_url="https://dashscope-intl.aliyuncs.com/compatible-mode/v1"
|
||
)
|
||
model = "qwen-plus" # oder qwen-max für höhere Qualität
|
||
```
|
||
|
||
### 3. Aggregator (`aggregator.py`)
|
||
|
||
**Funktion:** Erstellt Partei-Statistiken und Markdown-Reports.
|
||
|
||
**Reports:**
|
||
1. `partei-auswertung.md` — Detailreport mit Zitaten + Bandbreiten + Substanz-Problem
|
||
2. `parteienlandschaft.md` — Komprimierte Übersicht
|
||
3. `kandidaten-ranking.md` — Alle 27 Kandidat:innen im Einzelranking mit Kategorisierung
|
||
4. `wahlempfehlung.md` — Begründete Empfehlung + Substanz-Problem + Verweis auf Kandidat:innen
|
||
|
||
**Aggregations-Logik:**
|
||
- Durchschnittswerte pro Partei (GWÖ, Substanz, Wortanzahl)
|
||
- Bandbreiten pro Partei (Min–Max der Kandidat:innen)
|
||
- Ja-Quote berechnen
|
||
- Matrix-Felder aggregieren (häufigste pro Partei)
|
||
- Top-3-Zitate pro Partei extrahieren
|
||
- Kandidat:innen-Ranking mit Kategorisierung (Vorreiter / Solide / Schwach)
|
||
- Übergreifende Beobachtungen (Substanz-Problem, Bandbreiten-Analyse)
|
||
|
||
### 4. CLI (`cli.py`)
|
||
|
||
**Befehle:**
|
||
```
|
||
scrape Daten von URL laden
|
||
analyze LLM-Bewertung durchführen
|
||
aggregate Reports generieren
|
||
status Datenbankstatus anzeigen
|
||
export JSON-Export
|
||
run Vollständiger Workflow
|
||
```
|
||
|
||
## Datenbankschema
|
||
|
||
### Tabellen
|
||
|
||
```sql
|
||
kandidaten (id, vorname, nachname, plz, kommune, landkreis,
|
||
partei_raw, partei_normalisiert, ist_waehlergemeinschaft, pdf_url)
|
||
|
||
fragen (id, nummer, kurztext, volltext)
|
||
|
||
antworten_raw (id, kandidat_id, frage_id, antwort_kurz, antwort_erlaeuterung)
|
||
|
||
bewertungen (id, antwort_id, substanz_score, umfang, wortanzahl,
|
||
gwoe_score, gwoe_begruendung, matrix_felder,
|
||
staerken, schwaechen, model, bewertet_am)
|
||
```
|
||
|
||
### Views
|
||
|
||
```sql
|
||
v_partei_statistik -- Aggregierte Statistiken pro Partei
|
||
v_fragen_statistik -- Statistiken pro Frage
|
||
v_top_antworten -- Beste Antworten sortiert nach GWÖ-Score
|
||
```
|
||
|
||
## GWÖ-Matrix 2.0 Referenz
|
||
|
||
### Werte (Spalten)
|
||
1. Menschenwürde
|
||
2. Solidarität
|
||
3. Ökologische Nachhaltigkeit
|
||
4. Soziale Gerechtigkeit
|
||
5. Transparenz & Mitbestimmung
|
||
|
||
### Berührungsgruppen (Zeilen)
|
||
- A: Lieferant:innen, Dienstleister:innen
|
||
- B: Finanzpartner:innen, Steuerzahler:innen
|
||
- C: Politische Führung, Verwaltung
|
||
- D: Bürger:innen und Wirtschaft
|
||
- E: Staat, Gesellschaft, Natur
|
||
|
||
### Relevante Felder für Kommunalpolitik
|
||
- **D5**: Demokratische Einbindung (Bürgerbeteiligung)
|
||
- **D2**: Gesamtwohl der Gemeinde
|
||
- **C2**: Gemeinwohlorientierte Zielvereinbarung
|
||
- **A3/A4**: Nachhaltige/soziale Beschaffung
|
||
- **B5**: Partizipation in Finanzpolitik
|
||
|
||
## Reproduzierbarkeit
|
||
|
||
Das Tool ist vollständig reproduzierbar ohne Dotty-Beteiligung:
|
||
|
||
```bash
|
||
# Einmalige Einrichtung
|
||
cd ~/Nextcloud/dotty/projekte/2026-03-29\ Wahlprüfsteine\ _WIP_/wahlpruefsteine
|
||
python3 -m venv .venv
|
||
source .venv/bin/activate
|
||
pip install beautifulsoup4 requests openai
|
||
|
||
# Ausführung
|
||
python3 cli.py run
|
||
```
|
||
|
||
**Voraussetzungen:**
|
||
- Python 3.11+
|
||
- Qwen API-Key in Keychain (`security find-generic-password -s qwen-api -w`)
|
||
- Alternativ: `DASHSCOPE_API_KEY` Umgebungsvariable
|
||
|
||
## Kosten
|
||
|
||
- **Qwen Plus:** ~$0.0006 pro Bewertung
|
||
- **162 Bewertungen:** ~$0.10 gesamt
|
||
- **Modell-Alternativen:**
|
||
- `qwen-turbo`: günstiger, schneller, etwas weniger präzise
|
||
- `qwen-max`: teurer, höhere Qualität
|
||
|
||
## Erweiterungsmöglichkeiten
|
||
|
||
1. **Andere Datenquellen:** Scraper für andere Wahlprüfstein-Formate anpassen
|
||
2. **PDF-Reports:** WeasyPrint oder Quarto für ECOnGOOD-Design
|
||
3. **Zeitreihen:** Vergleich über mehrere Wahlen
|
||
4. **Interaktives Dashboard:** Streamlit oder FastAPI + SvelteKit
|
||
5. **Andere Bundesländer:** Partei-Mapping anpassen (CDU statt CSU etc.)
|
||
|
||
---
|
||
|
||
*Dokumentation erstellt: 29.03.2026*
|