Skip to content

Repository files navigation

psp-radar

Liest aus einer Shop-URL Shop-System und Zahlungsarten — verlässlich und mit Beleg zu jedem Fund. Dazu, wo es möglich ist, den Zahlungsabwickler.

Diese Reihenfolge ist keine Bescheidenheit, sondern Messergebnis. Über acht geprüfte Shops war das Shop-System 8 von 8 korrekt; der Abwickler ist ohne Checkout-Simulation nur bei etwa einem Viertel der DACH-Shops bestimmbar. Er lädt bei vielen Shops erst nach der Zahlungsauswahl — hinter der Grenze, die dieses Werkzeug nicht überschreitet. Zahlen und Methodik in docs/BEFUNDE.md.

Deshalb trägt jedes Ergebnis seine Belegart:

Belegart Bedeutung
im Checkout beobachtet Der Anbieter wurde beim Laden gesehen. Der stärkste Beleg
vom Händler angegeben Er nennt ihn selbst auf seiner Zahlungsseite. Eine Aussage, keine Messung
nur indirekte Spuren Hosts, Assets, Verbindungshinweise. Offen, wer die Karte abwickelt
nicht ermittelt Mit Begründung, was gefehlt hat

Nachfolger von psp-detector mit zwei neuen Schwerpunkten: teilbar ohne Installation und schnell genug für Listen.


Loslegen

Einmalig einrichten:

git clone https://github.com/roccostrobel/psp-radar.git
cd psp-radar
./einrichten.sh

Danach genügt ein Doppelklick auf start-lokal.command. Der Starter prüft die Umgebung, startet den Server und öffnet die Oberfläche. Fenster offen lassen, solange du das Tool nutzt.

Wenn etwas nicht stimmt, sagt es das vorher:

.venv/bin/psp-radar doctor

Zu GitHub Codespaces

Die Codespaces-Einrichtung liegt in .devcontainer/ und wird von der CI geprüft, hat aber in der Praxis nicht funktioniert — zwei Anläufe scheiterten an Umgebungsproblemen im Container, die als Erkennungsfehler erschienen. Bis das belastbar gelöst ist, ist der lokale Weg der empfohlene. Details in docs/CODESPACES.md.


Warum das nicht trivial ist

Der Zahlungsdienstleister ist auf der Startseite eines Shops fast immer unsichtbar. Er lädt erst im Checkout. Empirisch belegt am selben Shop:

snocks.com  ohne Checkout-Simulation  →  PSP nicht ermittelbar
snocks.com  mit Checkout-Simulation   →  Shopify Payments, 98 %

Und die naheliegende Abkürzung funktioniert nicht. Frühere Fassungen dieses Textes behaupteten, der CSP-Header eines Shops verrate den Anbieter, weil dort jede Checkout-Domain whitelistet sein muss. Gemessen über 15 DACH-Shops: 1 von 15 setzt überhaupt eine CSP, 0 von 15 lassen daraus den Acquirer ableiten. Die Behauptung war plausibel und ungeprüft.

Was ohne Checkout wirklich trägt, zusammengenommen:

Quelle Treffer bei 15 Shops
CSP-Header 0
preconnect / dns-prefetch 3 (alle Shopify)
Anbietername auf der Zahlungsseite 1
Kombination 4 = 27 %

Details und Methodik in docs/BEFUNDE.md.

Der Trichter bleibt trotzdem sinnvoll, nur mit realistischerer Erwartung:

Durchgang 1   alle URLs      ohne Browser        2–4 s     hohe Parallelität
              ↓ nur unklare Fälle
Durchgang 2   Rendering      geteilter Browser   15–25 s   mittlere
              ↓ nur weiterhin unklare
Durchgang 3   Checkout       geteilter Browser   40–70 s   niedrige

Jedes Ergebnis trägt sichtbar, aus welchem Durchgang es stammt. Zwei Treffer mit 96 % sind nicht gleichwertig, wenn einer aus einem HTTP-Header und einer aus beobachtetem Checkout-Traffic kommt.


Nutzung

# Einzelabfrage, Trichter (Standard)
psp-radar scan https://beispielshop.de

# Nur statisch — wenige Sekunden, ohne Browser
psp-radar scan https://beispielshop.de --statisch

# Volle Tiefe erzwingen
psp-radar scan https://beispielshop.de --voll --evidence

# Liste abarbeiten
psp-radar batch shops.csv -o ergebnisse.csv -c 6

# Oberfläche
psp-radar serve

# Erkennungsgüte messen
psp-radar eval

Die Oberfläche nimmt einzelne URLs und ganze Listen an und exportiert als CSV.


Architektur

core/      reine Logik — kein Netzwerk, kein Browser, keine Seiteneffekte
collect/   Beschaffung: httpx, Playwright, Plattform-Adapter
batch/     Trichter, Worker-Pool, Cache
eval/      Golden-Set, Fixtures, Messung
api/       FastAPI mit Zugangscode
web/       Oberfläche

core importiert nichts aus den anderen Schichten — erzwungen durch tests/test_architecture.py. Der Grund ist praktisch: Nur so lässt sich die gesamte Erkennung offline und deterministisch gegen eingefrorene Aufzeichnungen prüfen, ohne einen einzigen echten Shop anzufassen.

Nicht „in Sekunden", wie es hier vorher stand. Gemessen: 19 Sekunden pro Shop, reine Rechenzeit ohne Netz. Die Ursache sind html_regex-Signale, die über mehrere Megabyte Seitenquelltext laufen. Ein doppelter Durchgang über die gesamte Signaturdatenbank ist inzwischen entfernt (2 min → 58 s für drei Shops); der Rest ist echte Arbeit und noch nicht optimiert. Bei den angestrebten 30 Shops sind das rund zehn Minuten, und das ist zu viel für einen Lauf bei jedem Commit.

Confidence: Noisy-OR statt Addition

p = 1 − Π(1 − wᵢ · decay^i)

Addition würde aus fünf schwachen Indizien (5 × 20) scheinbare Gewissheit machen. Ein einzelner harter Treffer — Live-Key im Quelltext, Request an die Zahlungs-API — reicht allein. Viele weiche Treffer landen ehrlich bei wahrscheinlich.


Geschwindigkeit: drei Kategorien

Tempo wird nur dort geholt, wo es nichts kostet — und wo es etwas kostet, wird es gemessen.

Kategorie Maßnahmen Bedingung
kostenlos Warten auf Bedingungen statt auf Sekunden, geteilter Browser, Stufe 1 parallel Jederzeit. Verbessert auch die Zuverlässigkeit
kalibriert Trichter-Schwellwerte, früher Ausstieg Nur mit Nachweis gegen das Golden-Set
verworfen CSS blockieren, Checkout weglassen, Timeouts kürzen Nicht gemacht — Begründung in docs/DESIGN.md

Der Vorgänger enthielt 57 Sekunden fest verdrahtete Wartezeit über 33 Stellen. Ein sleep(3.0) nach „Zur Kasse" ist für schnelle Shops Verschwendung und für langsame zu kurz — also nicht nur langsam, sondern unzuverlässig. collect/waiting.py wartet stattdessen auf das Ereignis, auf das es ankommt.

Referenzwerte und Zielvorgaben: docs/BASELINE.md.


Zuverlässigkeit

Solche Tools scheitern nicht daran, dass sie nicht laufen, sondern daran, dass sie plausibel falsch liegen. Drei Tests halten das im Zaum:

  • test_safety.py — es wird nie eine Bestellung ausgelöst. Deckte im Vorgänger eine echte Lücke auf: „Kostenpflichtig bestellen" wäre geklickt worden
  • test_checkout_honesty.py — das Tool behauptet nie, weiter gekommen zu sein, als es kam. Im Vorgänger meldete es „Checkout erreicht ✓" für Shops, bei denen nicht einmal das Produkt im Warenkorb landete
  • test_architecture.py — die Schichtentrennung erodiert nicht durch einen naheliegenden Import

Dazu unbekannt mit Begründung statt geratenem Treffer, und eine Deckelung der Confidence, solange der Checkout nicht gesehen wurde.


Vier Sicherheitsschranken

Das Werkzeug klickt sich durch fremde Checkouts. Es löst nie eine Bestellung aus und gibt nie Zahlungsdaten ein. Ziel ist die Seite mit der Zahlungsauswahl, dort ist Schluss. Durchgesetzt an vier Stellen, jede mit eigenem Test in tests/test_safety.py:

Schranke Was sie verhindert
safe_click Klick auf einen Kaufbutton. Ohne ermittelbare Beschriftung wird gar nicht geklickt
safe_fill Eintrag in Karten-, IBAN-, CVC- oder Passwortfelder — auch keine Testdaten
safe_goto Navigation auf Bestellabschluss-Pfade wie /checkout/finish, auch per GET
AST-Prüfung Dass irgendwo im Code an safe_click vorbei geklickt wird

Die vierte ist die wichtigste: Die ersten drei schützen vor den Klicks, an die jemand gedacht hat. Sie fand bei ihrer Einführung drei echte Umgehungen — in adapters/base.py, shopware.py und render.py.

Der deutsche Rechtsrahmen hilft dabei: § 312j Abs. 3 BGB verlangt für Kaufbuttons eine eindeutige Beschriftung, weshalb praktisch jeder deutsche Kaufbutton „pflichtig" enthält. Ein einzelnes Muster deckt die ganze Familie ab. Die Sperrliste darf nur erweitert, nie gekürzt werden.

Fairness gegenüber den Shops

  • Rate-Limit pro Domain, nicht global. Vierzig Shops parallel sind unproblematisch; vierzig Zugriffe auf einen Shop nicht
  • robots.txt wird gelesen und respektiert
  • Identifizierbarer User-Agent
  • Ein Artikel im Warenkorb, Gast-Checkout mit erkennbar synthetischen Daten, keine Konten
  • Keine Speicherung personenbezogener Daten, keine Umgehung von Zugangsbeschränkungen

Lizenz

MIT — siehe LICENSE.

About

Ermittelt aus Shop-URLs den Zahlungsdienstleister, die Zahlungsarten und das Shop-System. Per Codespace teilbar, Trichter für Listen. DACH-Schwerpunkt.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages