#!/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) # {n4} — Sitzungs-Nr 4-stellig zero-gepadded (z.B. HB: b21l0033.pdf) 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" "BUND|19|BTP19-|https://dserver.bundestag.de/btp/19/19{n3}.xml" "BE|19|PlPr19-|https://www.parlament-berlin.de/ados/19/IIIPlen/protokoll/plen19-{n3}-pp.pdf" "BE|18|PlPr18-|https://www.parlament-berlin.de/ados/18/IIIPlen/protokoll/plen18-{n3}-pp.pdf" "TH|8|PlPr8-|https://www.thueringer-landtag.de/uploads/tx_tltcalendar/protocols/Arbeitsfassung{n}.pdf" "HB|21|HB21l-|https://www.bremische-buergerschaft.de/dokumente/wp21/land/protokoll/b21l{n4}.pdf" ) echo "=== auto-ingest-protocols $(date -Iseconds) ===" # ─── HH: Index-Page-Scrape statt URL-Pattern ────────────────────────── # Hamburg hat keine vorhersagbare URL-Pattern (Blob-IDs + Hashes). # Stattdessen: Index-Seite scrapen, jedes gefundene PDF einzeln ingesten. echo "--- HH WP23 (Index-Scrape) ---" docker exec -i "$CONTAINER" python <= 3: break continue consec_404 = 0 except urllib.error.HTTPError as e: if e.code == 404 or e.code == 403: consec_404 += 1 if consec_404 >= 3: break continue else: print(f" {pid}: HTTP {e.code}") continue except Exception as e: print(f" {pid}: {e}") continue print(f" → ingest {pid}") with tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) as tmp: tmp_path = Path(tmp.name) tmp_path.write_bytes(data) try: stats = asyncio.run(ingest_pdf( tmp_path, bundesland="BB", protokoll_id=pid, quelle_url=url, )) print(f" parsed: {stats['parsed']}, written: {stats['written']}") new_count += 1 except Exception as e: print(f" Fehler: {e}") finally: tmp_path.unlink(missing_ok=True) print(f" BB: {new_count} neue Protokolle ingestet") EOF 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") n4=$(printf "%04d" "$n") url="${pattern//\{n3\}/$n3}" url="${url//\{n4\}/$n4}" 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) ==="