LinkedIns öffentliche Stellenanzeigen sind eine ergiebige Quelle für Einstellungsdaten: Jobtitel, Unternehmen, Standorte, Veröffentlichungsdaten und die Suchfacetten, die anzeigen, wohin die Nachfrage sich entwickelt. Das Problem ist der programmatische Zugriff auf diese Daten. LinkedIn rendert seine Seiten clientseitig und stellt automatisierten Traffic hart vor Herausforderungen, sodass eine einfache HTTP-Anfrage eine leere Hülle statt Jobs zurückgibt. Dieser Leitfaden zeigt Ihnen, wie Sie öffentliche LinkedIn-Stellenanzeigen in Python scrapen: ein kleines, lauffähiges Skript, das die gerenderte Seite über die Crawling API abruft, die gewünschten Felder zieht und sie auf die Festplatte schreibt.

Um dies ehrlich zu halten, ist die gesamte Anleitung auf öffentliche Daten beschränkt: Stellenanzeigen, die jeder auf LinkedIns öffentlichen Job-Suchseiten ohne Anmeldung sehen kann. Sie berührt keine Konten, keine anmeldegeschützten Inhalte und keine persönlichen Profile. Der Rechtsabschnitt weiter unten benennt diese Grenze klar, und er ist kein Boilerplate, also lesen Sie ihn, bevor Sie dies auf reales Volumen richten.

Lesen Sie diesen Abschnitt zuerst, denn LinkedIn ist eines der sensibelsten Ziele im Web, und die ehrliche Antwort ist "Es kommt darauf an, und der Umfang ist enorm wichtig." Dieser Leitfaden ist bewusst auf öffentliche, nicht authentifizierte Stellenanzeigen beschränkt: die Seiten, die LinkedIn an jeden ausliefert, eingeloggt oder nicht, auf seiner öffentlichen Job-Suchoberfläche. Innerhalb dieses Rahmens sind einige Regeln nicht verhandelbar:

  • Scrapen Sie nicht hinter Authentifizierung. Wenn eine Seite eine Anmeldung zum Anzeigen erfordert, ist sie für diesen Leitfaden außer Reichweite. Keine Session-Cookies, keine Wiederverwendung von Zugangsdaten, keine Authentifizierungsumgehung jeglicher Art.
  • Sammeln Sie keine personenbezogenen Daten oder persönlichen Profile. Namen, Kontaktdaten, Verbindungsgraphen und einzelne Profilseiten sind tabu. Diese Anleitung sammelt Metadaten zu Stellenanzeigen, keine Daten über identifizierbare Personen.
  • Verstoßen Sie nicht gegen LinkedIns Nutzervereinbarung. Lesen Sie LinkedIns Nutzungsbedingungen und seine robots.txt, bevor Sie beginnen, und halten Sie sich daran. Respektieren Sie die angegebenen Rate-Erwartungen und halten Sie Ihr Anfragevolumen niedrig genug, dass Sie die Server niemanden belasten.

Zum rechtlichen Hintergrund: Im Fall hiQ Labs v. LinkedIn befassten sich US-Gerichte mit dem Scraping öffentlich verfügbarer Daten und stellten auf hoher Ebene fest, dass der Zugriff auf öffentliche Seiten an sich nicht gegen den Computer Fraud and Abuse Act verstößt. Dieser Fall wird oft als Rechtfertigung für das Scraping von LinkedIn zitiert, aber er ist keine pauschale Erlaubnis. Vertragsbedingungen (die Nutzervereinbarung), Datenschutzrecht und die Art der Datennutzung gelten weiterhin, und die Rechtslage verändert sich ständig. Behandeln Sie die Öffentlichkeitsdaten-Grenze als Mindestanforderung, nicht als Schlupfloch.

Nur öffentliche Stellendaten

Alles in diesem Leitfaden sammelt öffentliche Metadaten zu Stellenanzeigen: Jobtitel, Unternehmen, Standorte und Veröffentlichungsdaten, die jeder ohne Konto sehen kann. Es deckt keine anmeldegeschützten Daten, persönlichen Profile, Verbindungsdaten, Nachrichten oder Authentifizierungsumgehungen ab. Wenn Ihr Projekt mehr als öffentliche Stellenanzeigen benötigt, ist eine offizielle Partnerschaft oder Datenvereinbarung mit LinkedIn der richtige Weg, kein raffinierterer Scraper.

Warum eine einfache Anfrage bei LinkedIn scheitert

Fordern Sie eine LinkedIn-Job-Such-URL mit einem einfachen HTTP-Client an und Sie erhalten eine 200-Antwort mit fast keinen Jobdaten im Body. Zwei Dinge arbeiten gegen Sie. Erstens rendert LinkedIn seine Inserate im Browser mit JavaScript, sodass das anfängliche HTML eine Hülle ist, die sich erst füllt, nachdem die Skripte der Seite ausgeführt wurden. Zweitens markiert LinkedIn automatisierten Traffic schnell: Rechenzentrum-IPs und Anfragemuster, die nicht wie ein echter Besucher aussehen, werden herausgefordert oder blockiert, bevor sie den gerenderten Inhalt erreichen.

Ein funktionierender LinkedIn-Stellenanzeigen-Scraper braucht also zwei Dinge in einer einzigen Anfrage: einen Browser, der die Seite rendert, und eine IP, die die Plattform als echten Besucher liest. Sie können das selbst mit einem Headless-Browser und einem Pool aus rotierenden Residential-Proxys zusammensetzen, aber diesen Stack gesund zu halten ist der größte Teil der Arbeit. Die Crawling API fasst beides in einem Aufruf zusammen: Senden Sie ihr die URL mit einem JavaScript-Token, sie rendert die Seite hinter einer vertrauenswürdigen IP und gibt fertiges HTML zurück.

Warum ein JS-Token

Crawlbase bietet zwei Token-Typen. Das normale Token ruft statisches HTML ab; das JavaScript (JS)-Token rendert die Seite zunächst in einem echten Browser. LinkedIn wird clientseitig gerendert, also brauchen Sie hier das JS-Token. Das normale Token gibt dieselbe leere Hülle zurück, die eine einfache Anfrage ergeben würde.

Das Ziel verstehen: LinkedIns öffentliche Job-Such-URL

LinkedIns öffentliche Jobsuche befindet sich unter einer vorhersehbaren URL, deren Abfrageparameter direkt dem Suchformular entsprechen, sodass Sie jede Suche programmatisch erstellen können, ohne die UI zu bedienen. Hier ist ein konkretes Beispiel: Python-Entwickler-Stellen in London.

bash
https://www.linkedin.com/jobs/search?keywords=Python%20Developer&location=London

Die wichtigen Parameter:

  • keywords die gesuchte Stelle oder Fähigkeit, URL-kodiert.
  • location die Stadt, Region oder das Land, in dem gesucht werden soll.

Erstellen Sie die URL mit den gewünschten Parametern und Sie haben ein wiederholbares Ziel. Variieren Sie Keywords und Standort in einer Schleife und Sie haben einen Einstellungstrend-Job, der die öffentliche Nachfrage über die Zeit beobachtet.

Die Umgebung einrichten

Sie brauchen Python 3.8 oder höher. Bestätigen Sie Ihre Version, erstellen Sie eine virtuelle Umgebung, damit Projektabhängigkeiten isoliert bleiben, und installieren Sie dann die Bibliotheken.

bash
python --version

python -m venv linkedin_env
source linkedin_env/bin/activate

pip install crawlbase beautifulsoup4

Unter Windows aktivieren Sie die Umgebung mit linkedin_env\Scripts\activate statt der source-Zeile. Zwei Abhängigkeiten erledigen die Arbeit: crawlbase ist der offizielle Client für die Crawling API, und beautifulsoup4 parst das zurückgegebene HTML, damit Sie Felder daraus extrahieren können. Sie brauchen außerdem ein Crawlbase-Konto und ein JS-Token, das Sie nach der Registrierung im Dashboard erhalten. Setzen Sie es überall in den Code ein, wo Sie YOUR_CRAWLBASE_JS_TOKEN sehen.

Die gerenderte Job-Suchseite abrufen

Beginnen Sie damit, die fertige Seite zu laden. Sie übergeben zwei Optionen, die für eine Seite wie LinkedIn wichtig sind: ajax_wait weist die API an, auf das Laden asynchroner Inhalte zu warten, und page_wait hält für eine feste Anzahl von Millisekunden nach dem Laden an, damit spät rendernde Inserate Zeit haben zu erscheinen. Fünf Sekunden sind ein vernünftiger Ausgangspunkt; erhöhen Sie es, wenn die Ergebnisse spärlich zurückkommen.

python
from crawlbase import CrawlingAPI

api = CrawlingAPI({"token": "YOUR_CRAWLBASE_JS_TOKEN"})

options = {"ajax_wait": "true", "page_wait": 5000}

jobs_url = "https://www.linkedin.com/jobs/search?keywords=Python%20Developer&location=London"

def fetch_jobs_html(url):
    response = api.get(url, options)
    if response["status_code"] == 200:
        return response["body"].decode("utf-8")
    print("Failed to fetch the page. Status code:", response["status_code"])
    return None

html = fetch_jobs_html(jobs_url)
print(html[:500])

Führen Sie es aus und Sie sollten echtes Markup mit Job-Karten darin sehen, nicht die leere Hülle, die eine einfache Anfrage zurückgibt. Das bestätigt, dass das Rendering funktioniert, bevor Sie einen einzigen Selektor schreiben.

Crawlbase LinkedIn Scraper

LinkedIn braucht eine gerenderte Seite hinter einer vertrauenswürdigen IP, in einem Aufruf. Die Crawling API nimmt ein JS-Token, führt die Seite in einem echten Browser aus, rotiert serverseitig durch Residential-IPs und gibt Ihnen fertiges HTML, sodass Sie keinen eigenen Headless-Fleet und keinen Proxy-Pool betreiben müssen. Richten Sie es zunächst im kostenlosen Kontingent auf eine öffentliche Jobsuche.

Die Stellenanzeigen parsen

Mit dem HTML in der Hand laden Sie es in BeautifulSoup und durchlaufen die Job-Karten. Jede Karte auf der öffentlichen Suchseite enthält die gewünschten Felder: Jobtitel, Unternehmensname, Standort und Veröffentlichungsdatum. Inspizieren Sie die Live-Seite in den Entwicklertools Ihres Browsers, um die aktuellen Selektoren zu finden, und ordnen Sie dann jedes Feld einem davon zu.

python
from bs4 import BeautifulSoup

def extract_jobs(html):
    soup = BeautifulSoup(html, "html.parser")
    jobs = []

    for card in soup.select("div.base-card"):
        title = card.select_one("h3.base-search-card__title")
        company = card.select_one("h4.base-search-card__subtitle")
        location = card.select_one("span.job-search-card__location")
        posted = card.select_one("time")

        jobs.append({
            "title": title.get_text(strip=True) if title else "",
            "company": company.get_text(strip=True) if company else "",
            "location": location.get_text(strip=True) if location else "",
            "posted": posted["datetime"] if posted else "",
        })

    return jobs
Selektoren driften

LinkedIns Klassennamen ändern sich ohne Vorankündigung. Behandeln Sie die obigen Selektoren als Ausgangsmuster, nicht als Vertrag. Wenn die Extraktion leere Strings zurückgibt, inspizieren Sie erneut eine Live-öffentliche-Job-Suchseite und aktualisieren Sie die Selektoren. Das ist normale Wartung für jeden produktiven Scraper, kein Zeichen dafür, dass etwas kaputt ist.

Verbinden Sie Abruf und Parse in einer main-Funktion, damit Sie ein einziges lauffähiges Skript haben.

python
def main():
    html = fetch_jobs_html(jobs_url)
    if not html:
        return
    jobs = extract_jobs(html)
    for job in jobs:
        print(job)

if __name__ == "__main__":
    main()

Wie die Ausgabe aussieht

Führen Sie das vollständige Skript aus und Sie erhalten eine Liste strukturierter Job-Objekte. Ein gekürztes Beispiel:

json
[
  {
    "title": "Senior Python Developer",
    "company": "Monzo Bank",
    "location": "London, England, United Kingdom",
    "posted": "2026-01-14"
  },
  {
    "title": "Python Backend Engineer",
    "company": "Deliveroo",
    "location": "London, England, United Kingdom",
    "posted": "2026-01-12"
  }
]

Paginierung behandeln

Die öffentliche Jobsuche zeigt eine erste Charge von Inseraten und zeigt mehr beim Scrollen oder Blättern durch die Seiten. Der sauberste Weg, sie zu durchlaufen, ist der start-Abfrageparameter, der die Ergebnisse versetzt: start=0 ist die erste Seite, start=25 die nächste, und so weiter. Schleifen Sie den Offset, rufen Sie jede Seite über die Crawling API ab und sammeln Sie die Zeilen.

python
all_jobs = []
base = "https://www.linkedin.com/jobs/search?keywords=Python%20Developer&location=London"

for start in range(0, 75, 25):
    page_url = f"{base}&start={start}"
    html = fetch_jobs_html(page_url)
    if not html:
        break
    all_jobs.extend(extract_jobs(html))

print(f"Collected {len(all_jobs)} listings")

Halten Sie die Seitenanzahl bescheiden und takten Sie die Schleife. Drei Seiten zu durchlaufen, um eine Suche zu testen, ist etwas völlig anderes als Tausende von Offsets in einer engen Schleife zu durchlaufen, und das zweite Muster ist genau das, was einen Scraper drosselt.

Die Ergebnisse als CSV speichern

Das Drucken in die Konsole ist gut, während Sie iterieren, aber Sie möchten die Daten auf der Festplatte. Pythons eingebautes csv-Modul bildet jeden Objekt-Key auf eine Spalte ab und schreibt Ihre Zeilen in wenigen Zeilen, ohne zusätzliche Abhängigkeit.

python
import csv

def save_to_csv(jobs, path="linkedin_jobs.csv"):
    fields = ["title", "company", "location", "posted"]
    with open(path, "w", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=fields)
        writer.writeheader()
        writer.writerows(jobs)
    print(f"Saved {path}")

Rufen Sie save_to_csv(all_jobs) nach der Paginierungsschleife auf und jeder Lauf schreibt eine aufgeräumte linkedin_jobs.csv, die Sie in jeder Tabellenkalkulation öffnen oder in eine Pipeline laden können. Wenn Sie die Daten lieber mit SQL abfragen möchten, schreiben Sie dieselben Zeilen in eine SQLite-Tabelle; das Parsen bleibt identisch.

Ungeblockt bleiben

Selbst wenn das Rendering behandelt ist, beobachtet LinkedIn Scraper-artigen Traffic. Einige Gewohnheiten halten einen Lauf gesund, und sie gelten für jedes schwierige kommerzielle Ziel.

  • Dosieren Sie Ihre Anfragen. Dieselbe Suche in einer engen Schleife zu hämmern ist der schnellste Weg, gedrosselt zu werden. Verteilen Sie Anfragen und variieren Sie Ihre Keywords und Standorte.
  • Auf Rotation setzen. Ein Pool aus Residential-Proxys verteilt Anfragen auf viele echte Benutzeradressen, sodass keine einzelne ein Rate-Limit auslöst. Die Crawling API übernimmt das für Sie; wenn Sie Ihren eigenen Traffic routen möchten, gibt Ihnen der Smart AI Proxy dieselbe Residential-IP-Rotation als Drop-in-Proxy-Endpunkt.
  • Lesen Sie die Status-Codes. Ein Lauf, der anfängt, Herausforderungen oder Fehler zurückzugeben, sagt Ihnen, dass die aktuelle Rate oder IP-Stufe nicht mehr ausreicht. Behandeln Sie Proxy-Status-Fehlercodes als Signal, nicht als Rauschen, und schalten Sie zurück, wenn Sie sie sehen.

Das umfassendere Playbook finden Sie unter wie man Websites scrapt, ohne geblockt zu werden.

Zusammenfassung

Wichtigste Erkenntnisse

  • Bleiben Sie bei öffentlichen Stellendaten. Dieser Leitfaden sammelt nur öffentliche Metadaten zu Stellenanzeigen. Keine anmeldegeschützten Seiten, keine persönlichen Profile, keine Authentifizierungsumgehung; LinkedIns Nutzervereinbarung und robots.txt respektieren.
  • LinkedIn wird clientseitig gerendert. Eine einfache Anfrage gibt eine leere Hülle zurück, also muss die Seite gerendert werden, bevor sie geparst werden kann.
  • Sie brauchen Rendering und eine vertrauenswürdige IP zusammen. Die Crawling API mit einem JS-Token erledigt beides in einem Aufruf; ajax_wait und page_wait steuern, wie lange auf Inhalt gewartet wird.
  • Paginierung ist ein Offset. Den start-Parameter in Schritten von 25 erhöhen, um weitere Seiten öffentlicher Ergebnisse zu durchlaufen.
  • Rotieren und dosieren, um ungeblockt zu bleiben. Die Crawling API rotiert IPs für Sie; der Smart AI Proxy ist die Drop-in-Option, wenn Sie Ihren eigenen Traffic routen.

Häufig gestellte Fragen

Es kommt darauf an, was Sie scrapen und wie Sie es verwenden. Dieser Leitfaden bleibt streng bei öffentlichen, nicht authentifizierten Stellenanzeigen und vermeidet persönliche Profile, anmeldegeschützte Inhalte und Authentifizierungsumgehung. Selbst dort gelten LinkedIns Nutzervereinbarung, robots.txt und das anwendbare Datenschutzrecht. Der Fall hiQ v. LinkedIn befasste sich auf hoher Ebene mit dem Zugriff auf öffentliche Daten, ist aber keine pauschale Erlaubnis. Lesen Sie zuerst LinkedIns Bedingungen und beschränken Sie Ihren Umfang auf öffentliche Daten.

Warum gibt eine einfache Anfrage keine Stellendaten von LinkedIn zurück?

Weil LinkedIn seine Inserate clientseitig mit JavaScript rendert. Das anfängliche HTML ist eine Hülle, die sich erst füllt, nachdem die Skripte der Seite in einem Browser ausgeführt wurden, sodass eine rohe HTTP-Anfrage Status 200 mit den Stellenfeldern leer zurückgibt. Um echte Daten zu erhalten, muss die Seite zuerst gerendert werden, was das JS-Token der Crawling API für Sie übernimmt.

Brauche ich das normale Token oder das JS-Token für LinkedIn?

Das JS-Token. Das normale Token ruft statisches HTML ab, das auf LinkedIn dieselbe leere Hülle wie eine einfache Anfrage ist. Das JS-Token rendert die Seite in einem echten Browser, bevor es das HTML zurückgibt, sodass die Inserate vorhanden sind, wenn BeautifulSoup sie parst.

Meine Selektoren geben leere Strings zurück. Was hat sich geändert?

Mit großer Wahrscheinlichkeit das Markup von LinkedIn. Seine Klassennamen ändern sich ohne Vorankündigung, sodass Selektoren, die letzten Monat funktionierten, heute kaputt sein können. Inspizieren Sie eine Live-öffentliche-Job-Suchseite in den Entwicklertools Ihres Browsers erneut und aktualisieren Sie die Selektoren. Periodische Selektor-Wartung ist normal für jeden produktiven Scraper.

Wie vermeide ich Blocking beim Scrapen von LinkedIn?

Halten Sie Ihre Pro-IP-Anfragerate niedrig, variieren Sie Ihre Keywords und Standorte statt dieselbe URL zu schleifen, und leiten Sie über rotierende Residential-IPs weiter, sodass keine einzelne Adresse ein Rate-Limit auslöst. Die Crawling API verwaltet Rotation und einen vertrauenswürdigen IP-Pool für Sie; wenn Sie Ihren eigenen Stack aufbauen, gibt Ihnen der Smart AI Proxy diese Rotation als Drop-in-Endpunkt. Beobachten Sie die Status-Codes und schalten Sie zurück, wenn Herausforderungen erscheinen.

Kann ich LinkedIn-Profile oder Nachrichten damit scrapen?

Nein, und Sie sollten es nicht versuchen. Dieser Leitfaden ist absichtlich auf öffentliche Stellenanzeigen beschränkt. Persönliche Profile, Verbindungsdaten und Nachrichten liegen hinter Authentifizierung und beinhalten personenbezogene Daten, was hier außerhalb der Grenzen liegt. Wenn Ihr Projekt mehr als öffentliche Stellenanzeigen benötigt, streben Sie eine offizielle LinkedIn-Partnerschaft oder Datenvereinbarung an, statt authentifizierte Seiten zu scrapen.

Jetzt loslegen

Crawlen Sie jede Website im großen Maßstab, ohne gegen die Infrastruktur zu kämpfen.

Crawlbase übernimmt Proxys, Fingerprints und CAPTCHAs, damit Ihr Team Datenpipelines ausliefert, statt Crawl-Infrastruktur zu pflegen. 1.000 Anfragen kostenlos, keine Karte erforderlich.

Self-Service · Kein Verkaufsgespräch erforderlich · Enterprise-Crawl-Volumen verfügbar