Job-Radar
Ein selbst gebauter Job-Crawler, der IT-Stellen in der Region Ludwigsburg/Stuttgart von vielen Firmenportalen und Job-APIs einsammelt, filtert und bewertet, damit ich passende Einstiegsstellen finde, ohne täglich Dutzende Karriereseiten von Hand abzuklappern.
01Die Idee dahinter
Nach meiner Umschulung zur Fachinformatikerin für Systemintegration suche ich in der Region Ludwigsburg/Stuttgart nach einem Einstieg. Eine Besonderheit: Ich habe keinen Führerschein, deshalb ist die Erreichbarkeit mit Bahn und Bus ein echtes Kriterium bei der Bewertung von Arbeitgebern.
Statt jeden Tag viele Karriereseiten einzeln zu durchsuchen, sollte ein Programm die Stellen automatisch sammeln, Ausbildung/Praktika/Zeitarbeit herausfiltern und die für mich passenden Einstiegsjobs nach oben sortieren.
02Wie es aufgebaut ist
Das Herzstück ist ein Node.js-Backend, das aus rund 31 Quellen Stellen zieht und in einer lokalen SQLite-Datenbank ablegt. Ein Express-Server stellt eine kleine REST-API bereit, die ein schlankes „Job-Radar"-Dashboard im Browser versorgt. Vorgelagert findet ein Auto-Discovery-Schritt laufend neue Firmen in Reichweite von Bahn und Bus (siehe Kapitel 03).
Viele Quellenarten
Bundesagentur-API, Personio-XML, Behörden-RSS (service.bund.de), Workday, SmartRecruiters (Bosch) und Playwright-Scraper für JavaScript-lastige Karriereportale.
Auto-Discovery neuer Firmen
Ein Zusatz-Skript fragt OpenStreetMap nach Firmen in Reichweite von Bahn und Bus, prüft deren Karriereseiten und erkennt automatisch das Bewerbersystem (z. B. Personio). Neue Quellen finden sich so fast von selbst.
Umkreis nach ÖPNV
Orte werden über OpenStreetMap/Nominatim in Koordinaten umgewandelt, wichtig, weil ich auf Bahn und Bus angewiesen bin.
Schlaue Filter
Kontextbewusste Regex statt naiver Stichwortsuche: Ausbildung, Praktikum, Werkstudent und Zeitarbeit fliegen raus.
Dashboard „Job-Radar"
Dunkle Konsolen-Optik mit Signal-Meter-Score, Flag-Chips (fisi-match, junior, entry-level) und Quellen-Filter.
Rohdaten bleiben erhalten
Jede Anzeige speichert ihr rohes JSON mit, so lässt sich später neu auswerten, ohne erneut crawlen zu müssen.
03Auto-Discovery: neue Firmen finden
Am Anfang habe ich jede Firma von Hand in die Konfiguration eingetragen. Damit die Liste mitwächst, gibt es jetzt ein eigenes Skript, das passende Arbeitgeber selbst aufspürt, und zwar gezielt dort, wo ich ohne Auto hinkomme.
- Städte mit Bahn- und Bus-Anschluss als Ausgangspunkt: Ludwigsburg, Stuttgart, Ditzingen, Bietigheim-Bissingen, Waiblingen, Kornwestheim, Leonberg, Schwieberdingen, Korntal.
- OpenStreetMap/Overpass liefert Firmen und Betriebe in diesen Orten.
- Für jeden Kandidaten wird die Karriereseite geprüft und automatisch erkannt, welches Bewerbersystem (ATS) dahintersteckt, etwa ein Personio-Feed, den ich dann direkt und sauber anbinden kann.
- Treffer mit fertig nutzbarem Feed werden mit ★ markiert und lassen sich mit einem Handgriff in die Quellen-Konfiguration übernehmen.
So verwandelt sich das mühsame „Karriereseiten-Suchen" in einen halbautomatischen Schritt: Das Skript schlägt vor, ich entscheide, was in den Crawler wandert.
Der Discovery-Lauf findet nur Firmen und schreibt sie als Vorschlagsliste nach data/discovered.json. Er bindet sie nicht automatisch an. Erst wenn ich einen Kandidaten (besonders die ★-Treffer mit fertigem Feed) bewusst in die config.json übernehme, zieht der eigentliche Crawler (npm run crawl) auch dessen Stellen. So behalte ich die Kontrolle darüber, welche Quellen dauerhaft mitlaufen, statt tausend Kandidaten ungefiltert zu crawlen.
data/discovered.json · ★-Kandidaten sind sofort anbindbar04So bringt man es zum Laufen
Das Projekt läuft lokal unter Windows in der PowerShell. Kein Server, kein Build-System, nur Node.js. Einmalig werden die Abhängigkeiten installiert, danach genügen drei Befehle für den Ablauf Firmen finden → Stellen crawlen → Dashboard ansehen.
- In den Projektordner wechseln, dorthin, wo das Projekt liegt, z. B.
cd C:\Users\Benutzername\Downloads\jobcrawler\jobcrawler - Einmalig die Abhängigkeiten installieren mit
npm install, holt Node-Pakete wie Playwright und better-sqlite3 (nur beim ersten Mal oder nach Updates nötig). - Neue Firmen finden mit
npm run discover, fragt OpenStreetMap ab und prüft Karriereseiten (siehe Kapitel 03). - Stellen einsammeln mit
npm run crawl, zieht alle konfigurierten Quellen, filtert und bewertet. - Dashboard starten mit
npm run serve, danach im Browserhttp://localhost:3000aufrufen, um das „Job-Radar" zu öffnen.
PS C:\Users\Benutzername\Downloads\jobcrawler\jobcrawler> npm run discover > jobcrawler@0.1.0 discover > node src/discover.js [Ludwigsburg] frage OpenStreetMap ab... (via maps.mail.ru) [Ludwigsburg] 135 IT-Firmen in OSM verzeichnet [Stuttgart] 719 IT-Firmen in OSM verzeichnet [Ditzingen] 104 IT-Firmen in OSM verzeichnet [Waiblingen] 86 IT-Firmen in OSM verzeichnet [Leonberg] 67 IT-Firmen in OSM verzeichnet ... 1020 neue Kandidaten — prüfe Karriereseiten (dauert etwas)...
Der Discovery-Lauf kann bei über tausend Kandidaten ein paar Minuten dauern, jede Karriereseite wird höflich mit kleinen Pausen abgeklopft.
Screenshots






Aufnahmen vom Crawl-Lauf und vom „Job-Radar"-Dashboard folgen noch.
05Filter & Bewertung
Der interessanteste Teil ist, aus vielen Treffern die wirklich passenden herauszuholen. Statt einfacher Stichwortsuche arbeite ich mit kontextbewussten regulären Ausdrücken:
- Harte Ausschlüsse im Titel: Ausbildung, duales Studium, Umschulung, Praktikum, Werkstudent, Zeitarbeit/ANÜ, Abschlussarbeit, Ferienjob.
- Positiv-Scoring in der Beschreibung: Begriffe wie Junior, Berufseinsteiger, erste Berufserfahrung heben eine Stelle an.
- fisi-match (+5): greift, wenn eine Anzeige gezielt eine „Ausbildung als/zum Fachinformatiker Systemintegration" ausbildet bzw. sucht, für mich besonders relevant.
- Wortgrenzen verhindern Fehltreffer (z. B. „intern" in „International" wird nicht als Praktikum gewertet).
Doppelte Stellen erkennen
Damit dieselbe Stelle nicht mehrfach auftaucht, nutze ich die Referenznummer der Bundesagentur (refnr) als Schlüssel und, wenn es keine gibt, einen SHA1-Hash über den normalisierten Titel + Firma + Ort. Vorher werden Titel bereinigt (z. B. „(m/w/d)" entfernt), damit Varianten derselben Stelle zusammenfallen. Jede Anzeige speichert zusätzlich ihr rohes JSON, damit ich später neu auswerten kann, ohne erneut zu crawlen.
06Herausforderungen & Lösungen
Analytics-lastige Karriereseiten wurden mit „warte bis Netzwerk ruhig" nie fertig geladen und liefen in Timeouts.
Der Playwright-Scraper wartet auf domcontentloaded statt auf komplette Ruhe und läuft zusätzlich durch das Shadow DOM, um moderne Web-Components (versteckte Job-Listen) zu erreichen.
Manche Seiten (z. B. TransnetBW, W&W) geben trotz aller Kniffe keine Ergebnisse zurück, weil die Stellen erst per interner API im Browser nachgeladen werden.
Über die Entwicklertools des Browsers (F12 → Netzwerk → Fetch/XHR) lässt sich der interne JSON-Endpunkt aufspüren und direkt anbinden, zuverlässiger als das Scrapen der sichtbaren Seite. Ein paar dieser Fälle sind noch offen.
Beim Auto-Discovery lieferte der Overpass-Hauptserver plötzlich 406, und der Ausweich-Server war mit 500/502 überlastet. Ergebnis: null neue Kandidaten, obwohl am eigenen Code nichts falsch war.
Eine kurze Recherche zeigte: Das ist ein bekanntes, aktuelles Verhalten des Hauptservers, kein Fehler im eigenen Setup. Die Lösung aus der Community ist schlicht, mehrere Overpass-Spiegel nacheinander anzufragen und beim ersten zu bleiben, der antwortet, robuster gegen einzelne Ausfälle.
Reine Vermittler (z. B. „amaxo") verwässern die Ergebnisse und wurden aus der Quellenliste entfernt, ihre Alt-Einträge aus der Datenbank gelöscht.
07Was ich dabei gelernt habe
- Wie unterschiedlich Karriereportale technisch aufgebaut sind, von sauberen JSON-APIs bis zu tief verschachtelten Web-Components.
- Dass gute Filter- und Dedup-Logik mehr Arbeit macht als das eigentliche Crawlen und den größten Unterschied für die Nutzbarkeit ausmacht.
- Ein Blick auf Rechtliches: nur öffentlich zugängliche Daten,
robots.txtrespektieren, sich als Bot per User-Agent zu erkennen geben, und mit HR-Kontaktdaten in Anzeigen datensparsam umgehen (DSGVO).
08Ausblick
Das Projekt ist bewusst nie „fertig", es wächst mit meiner Jobsuche mit. Zwei Dinge rund um das Auto-Discovery stehen dabei im Fokus:
- Restzeit-Anzeige (schon eingebaut): Der Discovery-Lauf prüft über tausend Firmen und lief früher minutenlang ohne Rückmeldung. Jetzt zeigt er pro Firma eine Zeile mit laufender Nummer, gefundenem Bewerbersystem und einer „noch ~mm:ss min"-Schätzung, so sehe ich jederzeit, wo er steht.
- Parallele Prüfung (geplant): Momentan wird eine Firma nach der anderen geprüft, was bei über tausend Kandidaten dauert. Da es sich um viele verschiedene Firmenserver handelt (nicht einen einzigen), lassen sich mehrere gleichzeitig anfragen, ohne unhöflich zu werden: Jeder einzelne Server sieht weiterhin nur seine eine Anfrage. Blockaden entstehen durch Last pro Ziel, nicht durch die Gesamtgeschwindigkeit. Ein sanftes Limit (z. B. 4 gleichzeitig) würde den Lauf spürbar verkürzen. Da ich das Discovery ohnehin nur selten laufen lasse, hat es keine Eile.
