Erster vollwertiger Plenarprotokoll-Parser nach NRW. Quelle: https://dserver.bundestag.de/btp/{wp}/{wp}{n:03}.xml Anchor-Sprache (verifiziert WP20 Sitzungen 30 + 100): 'Die Beschlussempfehlung ist mit den Stimmen der Koalitionsfraktionen gegen die Stimmen der CDU/CSU-Fraktion bei Enthaltung der AfD-Fraktion angenommen.' Pattern: - Subjekt: Beschlussempfehlung | Ueberweisungsvorschlag | Antrag | Gesetzentwurf - Vote-Block: 'mit den Stimmen X / gegen die Stimmen Y / bei Enthaltung Z' - Ergebnis: 'angenommen' oder 'abgelehnt' - Drucksache rueckwaerts vom Anchor (1500 chars Window) - Kind 'ueberweisung' invertiert ergebnis zu 'ueberwiesen' Fraktions-Mapping (WP20 = Ampel): - 'Koalitionsfraktionen' → SPD + GRÜNE + FDP - 'Oppositionsfraktionen' → CDU/CSU + AfD + LINKE - 'CDU/CSU-Fraktion', 'Fraktion Bündnis 90/Die Grünen', etc. WP21 (ab 2025) braucht eigenes Mapping-Update. 26 Tests in test_protokoll_parsers_bund.py (Vote-Block-Parsing, Anchor- Erkennung, Drucksachen-Lookup, End-to-End mit Mock-XML). Cron + Ingest-CLI: - PROTO_TARGETS-Format erweitert um PROTOKOLL_ID_PREFIX und {n3}- Placeholder fuer 3-stellig zero-gepaddetes BT-Schema (BTP20-N) - ingest_votes URL-Suffix dynamisch (PDF vs XML) statt hardcoded .pdf - Eintrag in PROTOKOLL_PARSERS (NRW + BUND) - Stub-Test angepasst: BUND raus aus STUB_BL_CODES 889 Tests gruen (787 → 889, +102 fuer Phase-2 Stubs+Tests+BUND).
75 lines
2.9 KiB
Bash
Executable File
75 lines
2.9 KiB
Bash
Executable File
#!/bin/bash
|
|
# BL-uebergreifender Auto-Ingest fuer Plenarprotokolle (#106 / #126 Phase 3).
|
|
#
|
|
# Pro registriertem BL: liest letztes ingestetes Protokoll, probiert das
|
|
# naechste, ingestet bei 200, wiederholt bis 404 (mit GAP_TOLERANCE).
|
|
# Idempotent (Compound-PK in plenum_vote_results), kein State ausser DB.
|
|
#
|
|
# Wird via Cron taeglich morgens aufgerufen. Ausgabe nach
|
|
# /var/log/gwoe-ingest-protocols.log.
|
|
#
|
|
# Usage:
|
|
# auto-ingest-protocols.sh [CONTAINER]
|
|
set -euo pipefail
|
|
|
|
CONTAINER="${1:-gwoe-antragspruefer}"
|
|
GAP_TOLERANCE=3 # 3 aufeinanderfolgende 404 → fertig fuer dieses BL
|
|
|
|
# Pro BL: URL-Pattern + Wahlperiode-Auflistung.
|
|
# WP-Liste ergibt sich aus aktiven Wahlperioden in BUNDESLAENDER. Hier
|
|
# aktuell + Vorgaenger-WP, weil Plenum noch in der laufenden WP arbeitet
|
|
# und alte Sitzungen gelegentlich nachtraeglich digitalisiert werden.
|
|
#
|
|
# Format: BL_CODE|WAHLPERIODE|PROTOKOLL_ID_PREFIX|URL_PATTERN
|
|
# URL-Pattern unterstuetzt zwei Platzhalter:
|
|
# {n} — Sitzungs-Nr unkpaddet (z.B. NRW: MMP18-1.pdf)
|
|
# {n3} — Sitzungs-Nr 3-stellig zero-gepadded (z.B. BUND: 20001.xml)
|
|
PROTO_TARGETS=(
|
|
"NRW|18|MMP18-|https://www.landtag.nrw.de/portal/WWW/dokumentenarchiv/Dokument/MMP18-{n}.pdf"
|
|
"NRW|17|MMP17-|https://www.landtag.nrw.de/portal/WWW/dokumentenarchiv/Dokument/MMP17-{n}.pdf"
|
|
"BUND|20|BTP20-|https://dserver.bundestag.de/btp/20/20{n3}.xml"
|
|
)
|
|
|
|
echo "=== auto-ingest-protocols $(date -Iseconds) ==="
|
|
|
|
for entry in "${PROTO_TARGETS[@]}"; do
|
|
IFS='|' read -r bl wp prefix pattern <<< "$entry"
|
|
echo "--- ${bl} WP${wp} (prefix=${prefix}) ---"
|
|
|
|
# Hoechste bisher ingestete Sitzungs-Nr fuer diesen BL/Prefix
|
|
last_n=$(docker exec "$CONTAINER" python -c "
|
|
import sqlite3
|
|
c = sqlite3.connect('/app/data/gwoe-antraege.db').cursor()
|
|
c.execute(\"SELECT COALESCE(MAX(CAST(SUBSTR(quelle_protokoll, ${#prefix}+1) AS INTEGER)), 0) FROM plenum_vote_results WHERE bundesland=? AND quelle_protokoll LIKE ?\", ('${bl}', '${prefix}%'))
|
|
print(c.fetchone()[0])
|
|
" 2>/dev/null || echo "0")
|
|
# Sanity: numeric check
|
|
if ! [[ "$last_n" =~ ^[0-9]+$ ]]; then last_n=0; fi
|
|
|
|
start_n=$((last_n + 1))
|
|
echo "Letztes ingestes ${prefix}: ${last_n}, probiere ab ${start_n}"
|
|
|
|
consecutive_404=0
|
|
for n in $(seq $start_n $((last_n + 50))); do
|
|
n3=$(printf "%03d" "$n")
|
|
url="${pattern//\{n3\}/$n3}"
|
|
url="${url//\{n\}/$n}"
|
|
http=$(curl -sS -o /dev/null -w "%{http_code}" --max-time 15 "$url" || echo "000")
|
|
if [ "$http" = "200" ]; then
|
|
consecutive_404=0
|
|
pid="${prefix}${n}"
|
|
echo " → ingest ${pid}"
|
|
docker exec "$CONTAINER" python -m app.ingest_votes \
|
|
--url "$url" --bundesland "$bl" --protokoll-id "$pid" 2>&1 \
|
|
| tail -3 | sed 's/^/ /' || echo " !! ingest fehlgeschlagen"
|
|
elif [ "$http" = "404" ]; then
|
|
consecutive_404=$((consecutive_404 + 1))
|
|
if [ $consecutive_404 -ge $GAP_TOLERANCE ]; then
|
|
break
|
|
fi
|
|
fi
|
|
done
|
|
done
|
|
|
|
echo "=== auto-ingest done $(date -Iseconds) ==="
|