Blau beleuchtete Tastatur
// PROJEKT · CRAWLER & DASHBOARD

Job-Radar

● In Arbeit · wächst mit jeder neuen Quelle · jetzt mit Auto-Discovery

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.

Node.js (ES Modules) better-sqlite3 Express (REST-API) Playwright cheerio HTML / Vanilla JS

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).

[ Discovery ] -> [ Quellen ] -> [ Crawler ] -> [ Filter + Scoring ] -> [ SQLite ] -> [ API ] -> [ Dashboard ] OSM/Overpass APIs / Portale Playwright, Regex, Dedup, lokale DB Express Job-Radar ATS-Erkennung (~31 Firmen) cheerio, XML fisi-match

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.

So verwandelt sich das mühsame „Karriereseiten-Suchen" in einen halbautomatischen Schritt: Das Skript schlägt vor, ich entscheide, was in den Crawler wandert.

Wichtig: Discovery ≠ Crawl

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.

Ende des Discovery-Laufs mit Hinweis auf data/discovered.json und die Personio-Kandidaten
Ergebnis: data/discovered.json · ★-Kandidaten sind sofort anbindbar

04So 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.

  1. In den Projektordner wechseln, dorthin, wo das Projekt liegt, z. B. cd C:\Users\Benutzername\Downloads\jobcrawler\jobcrawler
  2. 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).
  3. Neue Firmen finden mit npm run discover, fragt OpenStreetMap ab und prüft Karriereseiten (siehe Kapitel 03).
  4. Stellen einsammeln mit npm run crawl, zieht alle konfigurierten Quellen, filtert und bewertet.
  5. Dashboard starten mit npm run serve, danach im Browser http://localhost:3000 aufrufen, um das „Job-Radar" zu öffnen.
Windows PowerShell
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:

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

Problem: Portale laden nie „fertig"

Analytics-lastige Karriereseiten wurden mit „warte bis Netzwerk ruhig" nie fertig geladen und liefen in Timeouts.

Lösung: früher weiterarbeiten + Shadow-DOM

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.

Problem: einzelne Portale liefern 0 Treffer

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.

Lösung: echte API-Endpunkte finden

Ü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.

Problem: OpenStreetMap-Server streikt

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.

Lösung: mehrere Spiegel-Server in Rotation

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.

Sauberkeit: Personalvermittler raus

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

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:

Hinweis: Privates Werkzeug für meine eigene Jobsuche, läuft lokal auf meinem Rechner. Es werden nur öffentlich zugängliche Stelleninformationen verarbeitet.
← Zurück zu den Projekten