8e19f6cffa
5 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
19e5fe4691 |
Phase J: SN EDAS-XML-Adapter (#26/#38) — Sachsen aktiv via XML-Export
Reaktiviert die in Phase J vertagte Adapter-Implementation: statt
ASP.NET-Postbacks zu simulieren (blockt durch __VIEWSTATE-Komplexität
plus robots.txt: Disallow: /), liest die neue ``SNEdasXmlAdapter``-
Klasse einen wöchentlich manuell aus EDAS exportierten XML-Dump.
Workflow:
1. User exportiert in der EDAS-Suchmaske mit Filter "Dokumententyp =
Antr" einen XML-Dump (bis zu 2500 Treffer/Export, sortiert
newest-first nach Datum)
2. Datei wird unter ``data/sn-edas-export.xml`` abgelegt (ins
persistent volume des prod-containers)
3. ``search()``/``get_document()`` lesen die XML-Datei lokal — keine
Server-Calls gegen edas.landtag.sachsen.de
4. ``download_text()`` resolved die echte PDF-URL on-demand über einen
einzelnen GET gegen ``viewer_navigation.aspx`` (single GET, kein
Postback) und holt dann das PDF von ``ws.landtag.sachsen.de/images``
XML-Schema (ISO-8859-1):
- ``<ID>`` interne EDAS-Doc-ID
- ``<Wahlperiode>``, ``<Dokumentenart>``, ``<Dokumentennummer>``
- ``<Fundstelle>`` z.B. ``"Antr CDU, BSW, SPD 01.10.2024 Drs 8/2"`` —
enthält Typ, Urheber und Datum, parsen via Regex
- ``<Titel>`` Volltext-Titel
PDF-URL-Schema (extrahiert aus dem viewer_navigation.aspx onLoad-
Handler): ``ws.landtag.sachsen.de/images/{wp}_Drs_{nr}_{...}.pdf``
mit variablen Suffix-Komponenten — wir machen die Resolution lazy.
Mapper-Erweiterung:
- ``parteien.PARTEIEN``-Tabelle um ``BÜNDNISGRÜNE``/``Bündnisgrüne``
ergänzt — der Sachsen-spezifische zusammengeschriebene Eigenname der
GRÜNEN-Fraktion (sonst wären 8/2100 etc. mit leerer Fraktionen-Liste
rausgekommen)
BL-Eintrag:
- ``SN.aktiv = True``
- ``doku_system="EDAS-XML-Export"`` (klare Klassifikation, dass es
KEIN normaler Webcrawler ist)
- Test ``test_sn_is_eigensystem_not_parldok`` umbenannt in
``test_sn_uses_xml_export_not_parldok``
Live-Probe lokal:
```
search('Klima', limit=5):
8/2100 2025-03-17 | [GRÜNE] | Fahrradoffensive Sachsen ...
7/192 2019-10-11 | [LINKE] | Erste Schritte zur Klimager...
7/2067 2020-03-19 | [CDU, SPD, GRÜNE] | Sächsische Waldbesitzer ...
```
176 Unit-Tests grün. Container braucht beim Deploy einen XML-Upload
ins data/-Volume — separater scp-Schritt.
Refs: #26, #38, #59 (Phase J revived)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
||
|
|
278d74ff97 |
Phase I: HB PARiSHBAdapter (#21/#33) — Bremen aktiv
Schließt #21 (HB-Scraper) und #33 (UI-Aktivierung). Eigenständige ``PARiSHBAdapter``-Klasse für paris.bremische-buergerschaft.de. Backend (HAR-Trace TEMP/paris.bremische-buergerschaft.de.har): - Single-POST gegen ``/starweb/paris/servlet.starweb`` mit form-urlencoded Body - ``path=paris/LISSHFL.web``, ``format=LISSH_BrowseVorgang_Report`` - ``01_LISSHFL_Themen=<query>`` (Volltext-Thesaurus) - ``02_LISSHFL_PARL=S OR L`` (Stadt + Landtag in einem Rutsch) - ``03_LISSHFL_WP=21`` (aktuelle Wahlperiode; Multi-WP-Range timeout-t den Server bei 60s) - Wildcards (``*``) timeout-en ebenfalls — bei leerer Query verwenden wir das hochfrequente Stoppwort ``"der"`` als Catch-all Hit-Format aus dem Single-Page-HTML: - ``<tbody name="RecordRepeater"><tr name="Repeat_TYP">`` - Title in ``<h2><a>`` - ``Drs <b>21/730 S</b>`` mit S/L-Suffix für Stadtbürgerschaft vs Landtag — Drucksachen-IDs werden als ``21/730S`` (ohne Space) gespeichert - ``Änderungsantrag vom 23.02.2026`` (Typ + Datum) - Fraktionen-Liste nach ``<br/>`` - PDF-Link mit ``target="new"`` auf bremische-buergerschaft.de Pipeline: - ``search()`` mit client-side ``"antrag"``-Filter (analog #61), fängt ``"Antrag"``, ``"Änderungsantrag"`` etc. - ``get_document()`` linearer Lookup - ``download_text()`` PDF-via-fitz BL-Eintrag in ``bundeslaender.py``: - ``HB.aktiv = True`` - ``doku_system="PARiS"`` (statt der alten Klassifikation "StarWeb" — PARiS ist eine deutlich abweichende Servlet-Variante, kein eUI) - ``drucksache_format="21/1234S"`` - Test ``test_hb_is_starweb_not_paris`` umbenannt in ``test_hb_is_paris_starweb_variant``, prüft jetzt auf "PARiS" Live-Probe: ``` 21/730S 2026-02-23 | [SPD,GRÜNE,LINKE] | Änderungsantrag | Haushaltsgesetze ... 21/1449 2025-11-05 | [SPD,GRÜNE,LINKE] | Antrag | Finanzierung der Bremischen Häfen 21/555S 2025-06-17 | [CDU] | Antrag | Clima-Campus zügig beantworten ``` 176 Unit-Tests grün, Live-Verifikation Sub-A im Container nach Deploy. Refs: #21, #33, #59 (Phase I) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
0f7d35f20e |
Phase G: BundestagAdapter via DIP-API (#56)
Schließt #56 (Bundespolitik überprüfbar machen). Neuer ``BundestagAdapter`` in ``app/parlamente.py``, neuer ``BUND``-Eintrag in ``app/bundeslaender.py`` als 17. Parlament-Slot. API: - DIP-Search-API auf ``search.dip.bundestag.de/api/v1/drucksache`` - API-Key aus ``dip-config.js`` gescraped (öffentlich, klartext) - Auth via URL-Param ``?apikey=...`` plus ``Origin: https://dip.bundestag.de``- Header (Origin-Locking, server-to-server-tauglich) - Pagination via ``cursor``-Parameter, 100 Hits pro Page - ``f.drucksachetyp=Antrag`` und ``f.wahlperiode=21`` als Server-Filter Mapping: - ``dokumentnummer`` → ``Drucksache.drucksache`` - ``titel`` → ``title`` - ``urheber[*].titel`` → durch ``parteien.extract_fraktionen`` zu ``["AfD"]``/``["GRÜNE"]``/etc. — die ``"Fraktion der AfD"``- Schreibweise wird vom zentralen Mapper aus #55 bereits korrekt geparst, kein Adapter-spezifisches Pattern nötig - ``fundstelle.pdf_url`` → ``link`` - ``datum`` → bereits ISO ``YYYY-MM-DD`` ``get_document(drucksache)`` nutzt ``f.dokumentnummer`` als direkter Server-Filter, kein linearer Pagination-Scan. BUND-Eintrag in ``bundeslaender.py``: - ``code="BUND"``, ``parlament_name="Deutscher Bundestag"``, ``wahlperiode=21``, ``wahlperiode_start="2025-03-25"`` (Konstituierung 21. WP nach BTW 2025), ``regierungsfraktionen=["CDU", "CSU", "SPD"]`` (Kabinett Merz) - ``aktiv=True`` — taucht automatisch in ``alle_bundeslaender()`` und ``aktive_bundeslaender()`` auf, damit die UI- und Auswertungs-Pipelines BUND ohne zusätzliche Sonderpfade kennen - 17 Einträge in ``BUNDESLAENDER`` statt 16 — Tests entsprechend aktualisiert (``test_sixteen_bundeslaender_plus_bund``, ``test_alle_bundeslaender_returns_all``, ``test_all_wahlperioden_lists_each_bl_twice``) Live-Probe direkt im Repo: ``` adapter: Deutscher Bundestag (DIP), wahlperiode=21 search returned 5 docs 21/5136 2026-03-31 | ['AfD'] | Transparenz, Wirtschaftlichkeit ... 21/5064 2026-03-27 | ['GRÜNE'] | Ausverkauf der Energieinfrastruktur ... 21/5059 2026-03-27 | ['AfD'] | Berufsfreiheit für Selbstständige ... get_document('21/5136') -> drucksache=21/5136 ``` 176 Unit-Tests grün, Live-Verifikation Sub-A im Container nach Deploy. Refs: #56, #59 (Phase G) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
db5a875d7c |
Activate Baden-Württemberg via PARLISAdapter (#29, Phase 1)
PARLIS auf parlis.landtag-bw.de läuft technisch auf demselben
eUI-Backend wie LSA-PADOKA und BE-PARDOK, hat aber drei wichtige
Unterschiede, die eine eigene Klasse statt einer PortalaAdapter-
Subklasse rechtfertigen:
1. Body-Schema: minimales lines mit l1/l2/l3/l4 (statt LSA/BE
2/3/4/10/11/20.x/90.x), serverrecordname=vorgang,
format=suchergebnis-vorgang-full, sort=SORT01/D SORT02/D SORT03,
keine parsed/json-Felder. Quelle: dokukratie/scrapers/portala.query.bw.json
plus HAR-Verifikation gegen die Live-Instanz.
2. Async polling: die initiale SearchAndDisplay-Antwort liefert nur
search_id mit status=running, KEINE report_id. Erst eine zweite
SearchAndDisplay-Anfrage mit id=<search_id> (ohne search-Component)
bekommt nach 1-3 Sekunden die report_id zurück. Reverse-engineered
aus esearch-ui.main.js requestReportOK() Z. ~1268.
3. Hit-Format: report.tt.html liefert Records als JSON-in-HTML-Comments
<!--{"WMV33":[...],"EWBV22":[...],...}-->. Komplett anderes Format
als LSA Perl-Dump oder BE HTML-Cards. Felder:
- EWBV22: "Drucksache 17/10323"
- EWBD05: direkter PDF-URL
- WMV33: Schlagworte (joined by ;)
- WMV30: Urheber-Kurzform
- EWBV23: "Antrag <Urheber> <DD.MM.YYYY>"
Smoke-Test (lokal):
BW q='': 8 hits in 17s, jüngste WP17-Anträge mit Datum + Fraktion
BW q='Schule': 8 hits, alle wirklich Schul-bezogen (Hochschule, Grundschule,
Schwimmunterricht, Lehrerbedarf etc.)
BW q='Klima': 8 hits, Klimaschutz/CO2/Energieberatung
get_document(17/10323): roundtrip funktioniert
bundeslaender.py: aktiv=True für BW; Anmerkung erweitert mit
PARLISAdapter-Verweis und drei-Unterschiede-Hinweis für künftige
Wartung. Test test_four_active_bundeslaender umbenannt zu
test_active_bundeslaender_include_phase_1_set, prüft jetzt nur
Subset-Bedingung statt exakter Count, damit Phase-1/2-Erweiterungen
keine Test-Updates brauchen.
Phase 1 (1/3) aus Roadmap-Issue #49.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
||
|
|
f98e64c734 |
Add pytest suite + fix two regex bugs uncovered by it (#46)
Erste Tests für die Codebase. 77 Tests, 0.08s Laufzeit, decken die
drei Bug-Klassen aus der April-2026-Adapter-Session ab plus haben
schon zwei weitere Bugs in Production-Code aufgedeckt.
## Setup
- requirements-dev.txt mit pytest + pytest-asyncio
- pytest.ini mit asyncio_mode=auto
- tests/conftest.py stubbt fitz/bs4/openai/pydantic_settings, damit
die Suite ohne den vollen prod-requirements-Satz läuft (pure unit
tests, kein PDF-Parsing, kein HTTP)
## Tests
- tests/test_parlamente.py (33 Tests)
* PortalaAdapter._parse_hit_list_cards: doctype/doctype_full
NameError-Regression aus
|