From 4cbe5de271990cc8bdac109e0bde289a6ce834b0 Mon Sep 17 00:00:00 2001 From: timpara Date: Mon, 20 Apr 2026 13:38:45 +0200 Subject: [PATCH] Verbesserungen an Dokumentation, OpenAPI-Spezifikation und Python-Beispiel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - openapi.yaml: Fehlenden Query-Parameter 'pav' (Private Arbeitsvermittlung) für /pc/v4/jobs und /pc/v4/app/jobs ergänzt. Dieser Parameter war im README dokumentiert, fehlte aber in der Spezifikation und damit auch im generierten Client. - openapi.yaml: Beschreibungen für mehrwertige Parameter 'befristung' und 'arbeitszeit' präzisiert. - api_example.py: 'verify=False' entfernt (TLS-Verifikation war unnötig deaktiviert und erzeugte InsecureRequestWarning). Timeout, Typ-Hints und 'raise_for_status()' für robustere Fehlerbehandlung ergänzt. Demo-Aufrufe in 'if __name__ == "__main__":' Block verschoben, damit das Modul importierbar ist, ohne Netzwerk-Requests auszulösen. - README.md: Tippfehler zu Beginn des Authentifizierungs-Abschnitts korrigiert ('ie' -> 'Die') und Konsistenz der Parameter-Markup- Formatierung für 'behinderung' und 'corona' hergestellt. --- README.md | 6 ++--- api_example.py | 67 +++++++++++++++++++++++++++++++------------------- openapi.yaml | 22 ++++++++++++++--- 3 files changed, 63 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 9029a94..e0cdecd 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Die Bundesagentur für Arbeit verfügt über die größte Datenbank für offene ## Authentifizierung -ie Authentifizierung funktioniert über die clientId: +Die Authentifizierung funktioniert über die clientId: **clientId:** jobboerse-jobsuche @@ -95,12 +95,12 @@ Angebotsart: 1=ARBEIT; 2=SELBSTAENDIGKEIT; 4=AUSBILDUNG/Duales Studium; 34=Prakt Befristung: 1 = befristet; 2 = unbefristet. Mehrere Semikolon-separierte Werte möglich (z.B. befristung=1;2). -Parameter: behinderung (Optional) +**Parameter:** *behinderung* (Optional) - false - true -Parameter: corona (Optional) +**Parameter:** *corona* (Optional) - false - true diff --git a/api_example.py b/api_example.py index 1bd7fbb..6895de6 100644 --- a/api_example.py +++ b/api_example.py @@ -1,4 +1,7 @@ import base64 +import urllib.parse +from typing import Any, Dict, Optional + import requests HEADERS = { @@ -8,8 +11,13 @@ 'Connection': 'keep-alive', } -def search(what, where): - """search for jobs. params can be found here: https://jobsuche.api.bund.dev/""" + +def search(what: str, where: str) -> Dict[str, Any]: + """Stellenanzeigen suchen. + + Die verfügbaren Parameter sind unter https://jobsuche.api.bund.dev/ + dokumentiert. + """ params = ( ('angebotsart', '1'), ('page', '1'), @@ -19,48 +27,57 @@ def search(what, where): ('was', what), ('wo', where), ) - response = requests.get('https://rest.arbeitsagentur.de/jobboerse/jobsuche-service/pc/v4/app/jobs', - headers=HEADERS, params=params, verify=False) + response = requests.get( + 'https://rest.arbeitsagentur.de/jobboerse/jobsuche-service/pc/v4/app/jobs', + headers=HEADERS, params=params, timeout=60) + response.raise_for_status() return response.json() -def get_job_details(refnr): - """Retrieve job details by refnr. The refnr is base64-encoded before sending.""" +def get_job_details(refnr: str) -> Dict[str, Any]: + """Jobdetails anhand der Referenznummer abrufen. + + Die ``refnr`` wird vor dem Aufruf Base64-kodiert. + """ encrypted = base64.b64encode(refnr.encode()).decode() response = requests.get( f'https://rest.arbeitsagentur.de/jobboerse/jobsuche-service/pc/v4/jobdetails/{encrypted}', - headers=HEADERS, verify=False) + headers=HEADERS, timeout=60) + response.raise_for_status() return response.json() -def get_employer_logo(kundennummer_hash): - """Retrieve employer logo by arbeitgeberKundennummerHash from job details. - Returns None if no logo is available (404). +def get_employer_logo(kundennummer_hash: str) -> Optional[bytes]: + """Arbeitgeberlogo anhand des ``arbeitgeberKundennummerHash`` abrufen. + + Gibt ``None`` zurück, wenn kein Logo für diesen Arbeitgeber hinterlegt + ist (HTTP 404). Dies ist ein regulärer Fall, kein Fehler. """ - import urllib.parse encoded_hash = urllib.parse.quote(kundennummer_hash, safe='') response = requests.get( f'https://rest.arbeitsagentur.de/vermittlung/ag-darstellung-service/ct/v1/arbeitgeberlogo/{encoded_hash}', - headers=HEADERS, verify=False) + headers=HEADERS, timeout=60) if response.status_code == 404: return None + response.raise_for_status() return response.content -result = search("bahn", "berlin") +if __name__ == "__main__": + result = search("bahn", "berlin") -refnr = result['stellenangebote'][0]["refnr"] -print("refnr:", refnr) + refnr = result['stellenangebote'][0]["refnr"] + print("refnr:", refnr) -details = get_job_details(refnr) -print("Titel:", details.get("stellenangebotsTitel") or details.get("titel")) + details = get_job_details(refnr) + print("Titel:", details.get("stellenangebotsTitel") or details.get("titel")) -kundennummer_hash = details.get("arbeitgeberKundennummerHash") -if kundennummer_hash: - logo = get_employer_logo(kundennummer_hash) - if logo: - print("Logo gefunden, Größe:", len(logo), "Bytes") + kundennummer_hash = details.get("arbeitgeberKundennummerHash") + if kundennummer_hash: + logo = get_employer_logo(kundennummer_hash) + if logo: + print("Logo gefunden, Größe:", len(logo), "Bytes") + else: + print("Kein Logo für diesen Arbeitgeber vorhanden.") else: - print("Kein Logo für diesen Arbeitgeber vorhanden.") -else: - print("Kein arbeitgeberKundennummerHash – kein Logo verfügbar.") + print("Kein arbeitgeberKundennummerHash – kein Logo verfügbar.") diff --git a/openapi.yaml b/openapi.yaml index c30a8a4..0f9dd3d 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -76,6 +76,13 @@ paths: example: true description: Gibt an, ob Jobs von Zeitarbeitsfirmen in die Suchergebnisse einbezogen werden sollen (default true). required: false + - in: query + name: pav + schema: + type: boolean + example: false + description: Private Arbeitsvermittlung. Gibt an, ob Jobs von privaten Arbeitsvermittlungen in die Suchergebnisse einbezogen werden sollen. + required: false - in: query name: angebotsart schema: @@ -97,7 +104,7 @@ paths: - 2 example: 1 required: false - description: Semikolon-separierte mehrere Werte möglich (z.B. befristung=1;2) 1 = befristet; 2 = unbefristet + description: "Befristung: 1 = befristet, 2 = unbefristet. Mehrere Werte können semikolon-separiert übergeben werden (z.B. befristung=1;2)." - in: query name: arbeitszeit schema: @@ -108,7 +115,7 @@ paths: - snw - ho - mj - description: Semikolon-separierte mehrere Werte möglich (z.B. arbeitszeit=vz;tz) vz=VOLLZEIT, tz=TEILZEIT, snw=SCHICHT_NACHTARBEIT_WOCHENENDE, ho=HEIM_TELEARBEIT, mj=MINIJOB + description: "Arbeitszeit: vz=VOLLZEIT, tz=TEILZEIT, snw=SCHICHT_NACHTARBEIT_WOCHENENDE, ho=HEIM_TELEARBEIT, mj=MINIJOB. Mehrere Werte können semikolon-separiert übergeben werden (z.B. arbeitszeit=vz;tz)." example: vz required: false @@ -201,6 +208,13 @@ paths: example: true description: Gibt an, ob Jobs von Zeitarbeitsfirmen in die Suchergebnisse einbezogen werden sollen (default true). required: false + - in: query + name: pav + schema: + type: boolean + example: false + description: Private Arbeitsvermittlung. Gibt an, ob Jobs von privaten Arbeitsvermittlungen in die Suchergebnisse einbezogen werden sollen. + required: false - in: query name: angebotsart schema: @@ -222,7 +236,7 @@ paths: - 2 example: 1 required: false - description: Semikolon-separierte mehrere Werte möglich (z.B. befristung=1;2) 1 = befristet; 2 = unbefristet + description: "Befristung: 1 = befristet, 2 = unbefristet. Mehrere Werte können semikolon-separiert übergeben werden (z.B. befristung=1;2)." - in: query name: arbeitszeit schema: @@ -233,7 +247,7 @@ paths: - snw - ho - mj - description: Semikolon-separierte mehrere Werte möglich (z.B. arbeitszeit=vz;tz) vz=VOLLZEIT, tz=TEILZEIT, snw=SCHICHT_NACHTARBEIT_WOCHENENDE, ho=HEIM_TELEARBEIT, mj=MINIJOB + description: "Arbeitszeit: vz=VOLLZEIT, tz=TEILZEIT, snw=SCHICHT_NACHTARBEIT_WOCHENENDE, ho=HEIM_TELEARBEIT, mj=MINIJOB. Mehrere Werte können semikolon-separiert übergeben werden (z.B. arbeitszeit=vz;tz)." example: vz required: false