JobBot ist ein experimentelles Projekt, das mit Unterstützung von Codex entstanden ist und für die Jobsuche in Deutschland verwendet werden kann. Die Anwendung bietet eine WPF-Oberfläche, durchsucht konfigurierbare Stellenquellen und speichert gefundene Jobs lokal in einer SQLite-Datenbank.
Der Bot ist als vorsichtiger Job-Aggregator gebaut, nicht als aggressiver Scraper:
- modulare Provider-Schnittstelle für Stellenquellen
- Provider für Arbeitsagentur und Remotive
- vorbereitete API-Provider für Adzuna und Jooble
- konfigurierbare Suchbegriffe, Standorte und Remote-Regeln
- Scoring mit stärker gewichteten Titel-Treffern und Keyword-Auswertung
- SQLite-Datenbank für Duplikaterkennung, Historie und Angeschaut-Status
- HTML- und CSV-Ergebnisdateien
- WPF-Viewer zum Anzeigen, Suchen, Öffnen und Markieren von Stellen
- optionaler Dauerlauf oder Windows-Aufgabenplanung
- xUnit-Testprojekt
- Windows
- .NET 8 Runtime oder SDK
Release-Builds werden über GitHub Actions auf Windows gebaut. Der Workflow erzeugt ein MSIX-Paket aus JobBot.Package und stellt es als Build-Artefakt bereit.
Öffentliche Release-Pakete sollen über SignPath Foundation signiert werden, sobald das Projekt dafür freigegeben ist. Bis dahin können MSIX-Pakete für Tests manuell über SignPath signiert werden. Selbstsignierte Testzertifikate sind nur für lokale Tests gedacht und müssen auf Zielsystemen vorher als vertrauenswürdig installiert werden.
Ein unsigned MSIX oder ein MSIX mit selbstsigniertem Testzertifikat ist nicht für eine öffentliche Weitergabe an Endnutzer vorgesehen.
Einmaliger Lauf:
dotnet run --project JobBot.csproj -- --onceStandardmäßig läuft der Bot einmalig, weil schedule.enabled in appsettings.json auf false steht.
Beim ersten Start wird die Vorlage appsettings.json aus dem Projektordner nach %LOCALAPPDATA%\Richter JobBot\appsettings.json kopiert. Danach arbeitet der Bot standardmäßig mit dieser aktiven Benutzer-Konfiguration.
Der Viewer liegt im Projekt JobBotViewer.
Start aus dem Projektordner:
dotnet run --project .\JobBotViewer\JobBotViewer.csprojIm Viewer kannst du:
- gespeicherte Ergebnisse aus der SQLite-Datenbank neu laden
- eine Suche starten
- Links öffnen
- Stellen als
Angeschautmarkieren - Stellen wieder auf
Neusetzen - Sucheinstellungen bearbeiten; Änderungen werden beim Verlassen des Tabs automatisch gespeichert
- im Tab
EinstellungenzwischenLightundDarkwechseln
Die Aktionsbuttons in der oberen Leiste sind nur im Tab Ergebnisse aktiv.
Neu bedeutet: Der Eintrag ist noch nicht als angeschaut markiert. Der Status bleibt Neu, bis du ihn selbst auf Angeschaut setzt.
Der Viewer ist nach MVVM aufgebaut:
MainWindow.xaml: OberflächeViewModels/MainWindowViewModel.cs: Viewer-LogikViewModels/JobRowViewModel.cs: TabellenzeilenInfrastructure/RelayCommand.cs: Button-CommandsApp.xaml.cs: zentrale Fehlerbehandlung für Viewer-Fehler
Die Ergebnis-Tabelle zeigt Remote nur noch als Hinweis, zum Beispiel Hybrid, Homeoffice möglich, Mobiles Arbeiten, Remote möglich oder Full Remote. Eine Remote-Prozent-Spalte gibt es nicht mehr, weil die Datenquellen dafür zu selten verlässliche Prozentwerte liefern.
Empfohlen für den Anfang. Nach dem Veröffentlichen kann die EXE per Aufgabenplanung gestartet werden:
dotnet publish JobBot.csproj -c Release --no-self-contained
.\bin\Release\net8.0\JobBot.exe "%LOCALAPPDATA%\Richter JobBot\appsettings.json" --onceDas mitgelieferte Script richtet eine tägliche Aufgabe ein:
powershell -ExecutionPolicy Bypass -File .\install-scheduled-task.ps1Ohne expliziten Namen legt das Script die Aufgabe mit Uhrzeit im Namen an, zum Beispiel JobBot Daily 08-00. Eine andere Uhrzeit oder ein eigener Name sind möglich:
powershell -ExecutionPolicy Bypass -File .\install-scheduled-task.ps1 -RunAt "07:30"
powershell -ExecutionPolicy Bypass -File .\install-scheduled-task.ps1 -TaskName "JobBot Daily Arbeitstag" -RunAt "07:30"Setze in der aktiven %LOCALAPPDATA%\Richter JobBot\appsettings.json:
"schedule": {
"enabled": true,
"runAtLocalTime": "08:00"
}Dann wartet der Bot im Prozess bis zur nächsten geplanten Uhrzeit und läuft danach täglich.
Standardmäßig werden Laufzeitdaten nicht im Projektordner gespeichert:
- aktive Konfiguration:
%LOCALAPPDATA%\Richter JobBot\appsettings.json - SQLite-Datenbank:
%LOCALAPPDATA%\Richter JobBot\jobbot.sqlite - Ergebnisdateien:
%LOCALAPPDATA%\Richter JobBot\results
Im Projektordner entstehen beim Entwickeln/Bauen weiterhin technische Ordner wie bin, obj, .vs.
JobBot überträgt Suchbegriffe, Orte und technische Abfrageparameter an die jeweils aktivierten Stellenquellen. Dazu gehören in der Standardkonfiguration insbesondere die Jobsuche der Bundesagentur für Arbeit; weitere Quellen wie Remotive, Adzuna oder Jooble werden nur genutzt, wenn sie in der Konfiguration aktiviert sind.
Gefundene Stellen werden lokal in einer SQLite-Datenbank gespeichert. Gespeichert werden unter anderem Provider, Job-ID, Titel, Firma, Ort, URL, Funddatum, Match-Score, erkannte Remote-/Homeoffice-Hinweise, Keyword-Begründungen und der lokale Angeschaut-Status.
JobBot betreibt keinen eigenen Serverdienst und lädt die lokale SQLite-Datenbank nicht an den Projektentwickler hoch. Bei aktivierten externen API-Providern gelten zusätzlich die Datenschutzbedingungen der jeweiligen Anbieter.
Die wichtigsten Bereiche in appsettings.json:
search.terms: Suchbegriffe wieWinForms Entwickler,WPF Entwickler,.NET Desktop Entwicklersearch.locations: Orte oder Regionen für die Suchesearch.remoteMode:Any,HybridOrRemoteoderRemoteOnlysearch.requireRemoteOutsideLocalLocations: wenntrue, werden außerhalb lokaler Orte Remote-/Homeoffice-Hinweise verlangtsearch.localLocationsWithoutRemoteRequirement: Orte, die auch ohne Remote-Hinweis akzeptiert werden, aktuellBerlinsearch.maxResultsPerProviderRun: maximale Roh-Treffer pro Provider-Laufscoring.minimumMatchPercent: Mindestscore für die Ausgabe, aktuell30scoring.titleWeight: Gewicht für Keyword-Treffer im Titel, aktuell2.2scoring.descriptionWeight: Gewicht für Keyword-Treffer in der Beschreibung, aktuell1.0scoring.remoteBonus: Bonus bei Remote-/Homeoffice-Hinweisproviders.arbeitsagentur: Arbeitsagentur-Quelle aktivieren, Page-Limit, Wartezeit und Detailabrufe steuernproviders.remotive: Remotive-Quelle aktivieren und Kategorie/Limit steuernproviders.adzuna: Adzuna mitappIdundappKeyaktivierenproviders.jooble: Jooble mitapiKeyaktivierenstorage.sqlitePath: Speicherort der SQLite-Datenbankreporting.outputDirectory: Ordner für HTML-/CSV-Ergebnisseviewer.theme:LightoderDarkfür den WPF-Viewer
Relative Pfade in der aktiven Settings-Datei werden relativ zur Settings-Datei aufgelöst. Windows-Variablen wie %LOCALAPPDATA% werden ebenfalls aufgelöst.
Das Scoring bewertet die fachliche Passung eines Jobs.
Wichtige Regeln:
- Pflichtkeywords werden in Titel und Beschreibung gesucht.
- Treffer im Titel zählen stärker als Treffer in der Beschreibung.
- Starke Keywords wie
winforms,windows forms,wpf,.net desktoperhöhen den Score deutlich. - Unterstützende Keywords wie
c#,.net,sql,mvvm,visual studioerhöhen den Score moderat. - Negative Keywords wie
java,php,praktikum,ausbildungschließen einen Job aus. - Remote-/Homeoffice-Hinweise geben einen Bonus, ersetzen aber keine fachliche Passung.
Die Begründungen werden in Console-, CSV-, HTML-Ausgabe und Viewer angezeigt, zum Beispiel:
title: wpfdescription: windows formsdescription support: c#remote/hybrid signalexcluded keyword: ausbildung
Nach jedem Lauf entstehen standardmäßig:
%LOCALAPPDATA%\Richter JobBot\results\latest-results.html%LOCALAPPDATA%\Richter JobBot\results\latest-results.csv%LOCALAPPDATA%\Richter JobBot\results\yyyy-MM-dd-results.html%LOCALAPPDATA%\Richter JobBot\results\yyyy-MM-dd-results.csv%LOCALAPPDATA%\Richter JobBot\results\latest-fetched.csv%LOCALAPPDATA%\Richter JobBot\results\yyyy-MM-dd-fetched.csv%LOCALAPPDATA%\Richter JobBot\results\latest-provider-debug.csv%LOCALAPPDATA%\Richter JobBot\results\yyyy-MM-dd-provider-debug.csv
latest-results.* enthält die finalen Treffer.
latest-fetched.csv enthält alle nicht ausgeschlossenen gefundenen Jobs inklusive Score, Provider, Link, Gründen und ob der Job in den finalen Treffern enthalten war. Diese Datei ist hilfreich, um Suchbegriffe und Scoring nachzuschärfen.
latest-provider-debug.csv zeigt pro Provider-Abfrage Suchbegriff, Ort, Seite, HTTP-Status, Anzahl der zurückgegebenen Rohjobs und einen gekürzten Response-Ausschnitt.
latest-fetched.csv wird standardmäßig nur aktualisiert, wenn der Lauf wirklich Jobs geholt hat. Dadurch überschreibt ein Netzwerkfehler oder leerer Lauf nicht die letzte brauchbare Diagnose-Datei. Die datierte yyyy-MM-dd-fetched.csv wird trotzdem für jeden Lauf geschrieben.
Aktuell eingebaut:
ArbeitsagenturJobProvider: nutzt die Jobsuche-Schnittstelle der Arbeitsagentur. Kein eigener API-Key des Nutzers erforderlich.RemotiveJobProvider: nutzt die öffentliche Remotive Remote-Jobs-API. Aktuell in der Standardkonfiguration deaktiviert.AdzunaJobProvider: vorbereitet für die Adzuna Jobs API. TrageappIdundappKeyein und setzeenabledauftrue.JoobleJobProvider: vorbereitet für die Jooble REST API. TrageapiKeyein und setzeenabledauftrue.
LinkedIn und XING werden bewusst nicht direkt automatisiert, weil deren öffentliche APIs nicht für freie Jobsuche gedacht sind und automatisiertes Scraping gegen deren Regeln laufen kann.
Der Arbeitsagentur-Provider ist vorsichtig gekapselt:
- Suchseiten werden sequenziell und mit konfigurierbarer Pause geladen.
- Treffer werden nach
Provider + ProviderJobIddedupliziert. - Detailabrufe passieren erst nach der Deduplizierung, damit derselbe Job nicht mehrfach detailliert geladen wird.
- HTTP-Fehler bei Suchseiten werden in der Provider-Debug-Datei sichtbar.
Die Bundesagentur selbst bietet nach aktuellem Stand keine offiziell garantierte Public-API für Drittanwendungen an. Deshalb sollte der Adapter leicht austauschbar bleiben.
Die SQLite-Datenbank wird automatisch angelegt. Sie speichert:
- Provider und Job-ID
- Titel, Firma, Ort, URL
- erstes und letztes Funddatum
- letzten Match-Score
- erkannten Remote-/Homeoffice-Hinweis
- letzte Begründung/Keyword-Treffer
is_viewed: bleibtfalse, bis du die Stelle im Viewer als angeschaut markierst
Die Duplikaterkennung basiert auf Provider + ProviderJobId.
Das Testprojekt liegt in JobBot.Tests und nutzt xUnit.
Tests ausführen:
dotnet test .\JobBot.Tests\JobBot.Tests.csprojAktuell werden unter anderem getestet:
- Scoring inklusive Titelgewichtung und Pflichtkeywords im Titel
- Remote-Hinweis-Erkennung
- Settings-Laden und Pfadauflösung
- Schedule-Berechnung
- SQLite-Repository
- Arbeitsagentur-Deduplizierung vor Detailabrufen
- Runner-Deduplizierung und Provider-Warnungen
Neue Quellen implementieren IJobProvider:
public sealed class MyJobProvider : IJobProvider
{
public string Name => "MyProvider";
public bool Enabled => true;
public Task<IReadOnlyList<JobPosting>> SearchAsync(
SearchSettings search,
CancellationToken cancellationToken)
{
// API abrufen, normalisierte JobPosting-Liste zurückgeben.
}
}Danach den Provider in Program.cs zur Providerliste hinzufügen.
Neufachlich getrennt vonAngeschautspeichern, falls später beide Informationen separat gebraucht werden- Suchplan statt Kreuzprodukt aus
terms x locations - Provider-Debug für Detailabrufe erweitern
- zusätzliche Provider für Firmenkarriereseiten oder weitere Job-APIs
- E-Mail- oder Desktop-Benachrichtigung
- Profilgewichtung nach Wunsch-Arbeitsort, Gehalt oder Seniorität
