Beschlussprotokoll-Parser: BL-übergreifende Abstimmungsergebnis-Extraktion #126

Open
opened 2026-04-12 11:07:05 +02:00 by tobias · 0 comments
Owner

Kontext

Aus der #106-Research (Abstimmungsverhalten) stellte sich heraus, dass die Beschlussprotokolle der Plenarsitzungen eine wesentlich bessere Datenquelle sind als die ausführlichen Plenarprotokolle (PDF). Beschlussprotokolle sind kurze, strukturierte Zusammenfassungen mit exaktem Abstimmungsergebnis + Fraktions-Breakdown pro TOP.

NRW-Proof-of-Concept (MMPB18-*.html): 90 LOC Python-Parser, validiert auf 9 Protokollen. Findet pro Sitzung alle Abstimmungen mit Ergebnis + ja/nein/enthaltung pro Fraktion. Kein PDF-Parsing nötig (strukturiertes HTML).

Ziel

Ein eigenständiger, BL-übergreifender Beschlussprotokoll-Parser, der:

  • Für jedes Parlament mit verfügbarem Beschlussprotokoll die Abstimmungsergebnisse extrahiert
  • In eine einheitliche Datenstruktur überführt: {drucksache, ergebnis, ja, nein, enthaltung, sitzung, datum, bundesland}
  • Unabhängig vom GWÖ-Antragsprüfer nutzbar ist (eigenes Modul, kann aber in die Webapp integriert werden)

BL-Recherche-Ergebnis (Stand 2026-04-12)

Trivial parsbar (strukturiertes HTML mit Fraktions-Votes)

BL URL-Pattern Format Aufwand
NRW landtag.nrw.de/.../MMPB18-{nr}.html HTML-Tabelle (4 Spalten) POC fertig (90 LOC)
SL landtag-saar.de/aktuelles/mitteilungen/abstimmungsergebnisse-der-{xx}-landtagssitzung-vom-{datum}/ HTML-Webseite, Fraktionen in Klammern [SPD: dafür; CDU: dagegen; AfD: Enthaltung] trivial

Mittel (PDF mit Textebene, Fraktions-Votes wahrscheinlich enthalten)

BL URL-Pattern Format Aufwand
MV dokumentation.landtag-mv.de/parldok/dokument/{id}/...beschlussprotokoll... PDF mittel
SH landtag.ltsh.de/.../beschlusspro/{jahr}/bp_20-{nr}_{mm}-{yy}.pdf PDF mittel
BB parlamentsdokumentation.brandenburg.de/.../beschlpr/protokolle/{nr}.pdf PDF mittel
RP dokumente.landtag.rlp.de/landtag/plenarprotokolle/b-{nr}-P-18.pdf PDF mittel
HH hamburgische-buergerschaft.de/.../vorlaeufiges-beschlussprotokoll-data.pdf PDF mittel
HE starweb.hessen.de/cache/.../Beschlussprotokoll_PL_{nr}_{datum}.pdf PDF mittel
HB bremische-buergerschaft.de/dokumente/wp21/land/protokoll/b21l{nr}.pdf PDF mittel
BUND bundestag.de/dokumente/protokolle/amtlicheprotokolle/... HTML + namentliche als XLSX mittel (Kombination zweier Quellen)

Hoch / nicht verfügbar (kein Beschlussprotokoll mit Fraktions-Votes)

BL Situation Alternative
BE Beschlussprotokoll-PDF hat kein direktes Fraktionsvoting Plenarprotokoll-PDF parsen
LSA Kein Beschlussprotokoll, nur namentliche Abstimmungen (Einzelpersonen) in PADOKA PADOKA namentliche → Fraktions-Aggregation
BW Beschlüsse-PDF ohne Fraktionen; namentliche separat in PARLIS (CSV verfügbar!) PARLIS-CSV für namentliche
TH Kein Beschlussprotokoll, nur Volltext-Plenarprotokoll PDF-Plenarprotokoll parsen (wie NRW v5-v7)
BY Kein Beschlussprotokoll, Abstimmungslisten als gescannte Grafiken (OCR nötig) Plenarprotokoll-PDF parsen
SN HTML-Beschlüsse vorhanden, aber nur angenommen/abgelehnt ohne Fraktionen Plenarprotokoll-PDF parsen
NI Kein eigenständiges Beschlussprotokoll Stenografischer Bericht (PDF) parsen

Zusammenfassung

Kategorie Anzahl Parlamente
Trivial (struct. HTML mit Fraktionen) 2 NRW , SL
Mittel (PDF mit Text-Ebene) 8 MV, SH, BB, RP, HH, HE, HB, BUND
Hoch (kein Beschlussprotokoll oder keine Fraktionen) 7 BE, LSA, BW, TH, BY, SN, NI

Implementierungs-Reihenfolge

Phase 1 — Trivial (sofort umsetzbar)

  • NRW HTML-Parser (POC fertig, /tmp/beschluss_parser_v2.py)
  • SL HTML-Parser

Phase 2 — PDF-Beschlussprotokolle

  • RP (OPAL-basiert, ähnlich NRW)
  • SH, HB (klare URL-Patterns)
  • MV, BB (ParlDok/portala)
  • HH, HE
  • BUND (amtliches Protokoll + namentliche)

Phase 3 — Fallback auf Plenarprotokoll-PDF (nur wenn nötig)

  • TH, BY, NI (Volltext-Parser nach NRW-v7-Vorbild)
  • BE, SN (Volltext oder spezielle Quellen)
  • LSA (PADOKA namentliche → Fraktions-Aggregation)
  • BW (PARLIS-CSV für namentliche)

Architektur-Vorschlag

app/protocols/
├── __init__.py
├── base.py                # ProtocolParser ABC
├── models.py              # Vote Pydantic-Model
├── nrw_beschluss.py       # NRW HTML-Beschlussprotokoll
├── sl_beschluss.py        # SL HTML-Abstimmungsergebnisse
├── pdf_beschluss.py       # Basis-Parser für PDF-Beschlussprotokolle
├── nrw_plenar.py          # NRW PDF-Plenarprotokoll (v7, Fallback)
└── bundestag.py           # DIP-API + namentliche

# DB-Schema
CREATE TABLE parliament_votes (
    id INTEGER PRIMARY KEY,
    drucksache TEXT NOT NULL,
    bundesland TEXT NOT NULL,
    sitzung TEXT,
    datum TEXT,
    ergebnis TEXT,
    votes_json TEXT,
    quelle_url TEXT,
    indexed_at TEXT
);

Code-Stand

  • NRW HTML-Parser: /tmp/beschluss_parser_v2.py (~90 LOC) — validiert auf 9 Sitzungen, alle 5 Fraktionen korrekt erkannt inkl. ja/nein-Flip bei Ablehnungen
  • NRW PDF-Parser: /tmp/parser_v5.py (~390 LOC) — als Fallback für BL ohne Beschlussprotokoll
  • Fixture: /tmp/nrw_fixture.json — 19 Ground-Truth-Einträge für Cross-Validation

Akzeptanzkriterien

  • NRW + SL HTML-Parser in Webapp integriert (Modul + DB + API)
  • ≥5 PDF-BL-Beschlussprotokolle parsbar (Phase 2)
  • UI-Sektion "🗳 Abstimmungsergebnis" im Detail-Panel wenn Daten vorhanden
  • Nightly-Indexing-Job für neue Sitzungen
## Kontext Aus der #106-Research (Abstimmungsverhalten) stellte sich heraus, dass die **Beschlussprotokolle** der Plenarsitzungen eine wesentlich bessere Datenquelle sind als die ausführlichen Plenarprotokolle (PDF). Beschlussprotokolle sind kurze, strukturierte Zusammenfassungen mit exaktem Abstimmungsergebnis + Fraktions-Breakdown pro TOP. **NRW-Proof-of-Concept (MMPB18-*.html):** 90 LOC Python-Parser, validiert auf 9 Protokollen. Findet pro Sitzung alle Abstimmungen mit Ergebnis + ja/nein/enthaltung pro Fraktion. Kein PDF-Parsing nötig (strukturiertes HTML). ## Ziel Ein **eigenständiger, BL-übergreifender Beschlussprotokoll-Parser**, der: - Für jedes Parlament mit verfügbarem Beschlussprotokoll die Abstimmungsergebnisse extrahiert - In eine einheitliche Datenstruktur überführt: `{drucksache, ergebnis, ja, nein, enthaltung, sitzung, datum, bundesland}` - Unabhängig vom GWÖ-Antragsprüfer nutzbar ist (eigenes Modul, kann aber in die Webapp integriert werden) ## BL-Recherche-Ergebnis (Stand 2026-04-12) ### Trivial parsbar (strukturiertes HTML mit Fraktions-Votes) | BL | URL-Pattern | Format | Aufwand | |---|---|---|---| | **NRW** | `landtag.nrw.de/.../MMPB18-{nr}.html` | HTML-Tabelle (4 Spalten) | **POC fertig** (90 LOC) | | **SL** | `landtag-saar.de/aktuelles/mitteilungen/abstimmungsergebnisse-der-{xx}-landtagssitzung-vom-{datum}/` | HTML-Webseite, Fraktionen in Klammern `[SPD: dafür; CDU: dagegen; AfD: Enthaltung]` | **trivial** | ### Mittel (PDF mit Textebene, Fraktions-Votes wahrscheinlich enthalten) | BL | URL-Pattern | Format | Aufwand | |---|---|---|---| | **MV** | `dokumentation.landtag-mv.de/parldok/dokument/{id}/...beschlussprotokoll...` | PDF | mittel | | **SH** | `landtag.ltsh.de/.../beschlusspro/{jahr}/bp_20-{nr}_{mm}-{yy}.pdf` | PDF | mittel | | **BB** | `parlamentsdokumentation.brandenburg.de/.../beschlpr/protokolle/{nr}.pdf` | PDF | mittel | | **RP** | `dokumente.landtag.rlp.de/landtag/plenarprotokolle/b-{nr}-P-18.pdf` | PDF | mittel | | **HH** | `hamburgische-buergerschaft.de/.../vorlaeufiges-beschlussprotokoll-data.pdf` | PDF | mittel | | **HE** | `starweb.hessen.de/cache/.../Beschlussprotokoll_PL_{nr}_{datum}.pdf` | PDF | mittel | | **HB** | `bremische-buergerschaft.de/dokumente/wp21/land/protokoll/b21l{nr}.pdf` | PDF | mittel | | **BUND** | `bundestag.de/dokumente/protokolle/amtlicheprotokolle/...` | HTML + namentliche als XLSX | mittel (Kombination zweier Quellen) | ### Hoch / nicht verfügbar (kein Beschlussprotokoll mit Fraktions-Votes) | BL | Situation | Alternative | |---|---|---| | **BE** | Beschlussprotokoll-PDF hat kein direktes Fraktionsvoting | Plenarprotokoll-PDF parsen | | **LSA** | Kein Beschlussprotokoll, nur namentliche Abstimmungen (Einzelpersonen) in PADOKA | PADOKA namentliche → Fraktions-Aggregation | | **BW** | Beschlüsse-PDF ohne Fraktionen; namentliche separat in PARLIS (CSV verfügbar!) | PARLIS-CSV für namentliche | | **TH** | Kein Beschlussprotokoll, nur Volltext-Plenarprotokoll | PDF-Plenarprotokoll parsen (wie NRW v5-v7) | | **BY** | Kein Beschlussprotokoll, Abstimmungslisten als **gescannte Grafiken** (OCR nötig) | Plenarprotokoll-PDF parsen | | **SN** | HTML-Beschlüsse vorhanden, aber nur angenommen/abgelehnt **ohne Fraktionen** | Plenarprotokoll-PDF parsen | | **NI** | Kein eigenständiges Beschlussprotokoll | Stenografischer Bericht (PDF) parsen | ## Zusammenfassung | Kategorie | Anzahl | Parlamente | |---|---|---| | **Trivial** (struct. HTML mit Fraktionen) | **2** | NRW ✅, SL | | **Mittel** (PDF mit Text-Ebene) | **8** | MV, SH, BB, RP, HH, HE, HB, BUND | | **Hoch** (kein Beschlussprotokoll oder keine Fraktionen) | **7** | BE, LSA, BW, TH, BY, SN, NI | ## Implementierungs-Reihenfolge ### Phase 1 — Trivial (sofort umsetzbar) - [x] NRW HTML-Parser (POC fertig, `/tmp/beschluss_parser_v2.py`) - [ ] SL HTML-Parser ### Phase 2 — PDF-Beschlussprotokolle - [ ] RP (OPAL-basiert, ähnlich NRW) - [ ] SH, HB (klare URL-Patterns) - [ ] MV, BB (ParlDok/portala) - [ ] HH, HE - [ ] BUND (amtliches Protokoll + namentliche) ### Phase 3 — Fallback auf Plenarprotokoll-PDF (nur wenn nötig) - [ ] TH, BY, NI (Volltext-Parser nach NRW-v7-Vorbild) - [ ] BE, SN (Volltext oder spezielle Quellen) - [ ] LSA (PADOKA namentliche → Fraktions-Aggregation) - [ ] BW (PARLIS-CSV für namentliche) ### Architektur-Vorschlag ``` app/protocols/ ├── __init__.py ├── base.py # ProtocolParser ABC ├── models.py # Vote Pydantic-Model ├── nrw_beschluss.py # NRW HTML-Beschlussprotokoll ├── sl_beschluss.py # SL HTML-Abstimmungsergebnisse ├── pdf_beschluss.py # Basis-Parser für PDF-Beschlussprotokolle ├── nrw_plenar.py # NRW PDF-Plenarprotokoll (v7, Fallback) └── bundestag.py # DIP-API + namentliche # DB-Schema CREATE TABLE parliament_votes ( id INTEGER PRIMARY KEY, drucksache TEXT NOT NULL, bundesland TEXT NOT NULL, sitzung TEXT, datum TEXT, ergebnis TEXT, votes_json TEXT, quelle_url TEXT, indexed_at TEXT ); ``` ## Code-Stand - **NRW HTML-Parser:** `/tmp/beschluss_parser_v2.py` (~90 LOC) — validiert auf 9 Sitzungen, alle 5 Fraktionen korrekt erkannt inkl. ja/nein-Flip bei Ablehnungen - **NRW PDF-Parser:** `/tmp/parser_v5.py` (~390 LOC) — als Fallback für BL ohne Beschlussprotokoll - **Fixture:** `/tmp/nrw_fixture.json` — 19 Ground-Truth-Einträge für Cross-Validation ## Akzeptanzkriterien - [ ] NRW + SL HTML-Parser in Webapp integriert (Modul + DB + API) - [ ] ≥5 PDF-BL-Beschlussprotokolle parsbar (Phase 2) - [ ] UI-Sektion "🗳 Abstimmungsergebnis" im Detail-Panel wenn Daten vorhanden - [ ] Nightly-Indexing-Job für neue Sitzungen
tobias added this to the post-1.0 milestone 2026-04-25 20:59:57 +02:00
Sign in to join this conversation.
No description provided.