Hur du skrapar Indeed med Python (och undviker 403-fel) 2026

Senast uppdaterad April 22, 2026
Hur du skrapar Indeed med Python (och undviker 403-fel) 2026

Någonstans runt min femtionde kopiera-och-klistra av en jobbtitel från Indeed till ett kalkylark började jag ifrågasätta mina karriärval. Om du någon gång har försökt hämta strukturerad data från Indeed programmatiskt känner du redan till poängen: 403-felet är inte en bugg — det är en funktion i InDeeds försvarssystem.

Indeed är världens största jobbplattform, med ungefär 350 miljoner unika besökare per månad, 130 miljoner jobbannonser vid varje given tidpunkt och verksamhet i över 60 länder. Det gör den till en av de rikaste källorna till data om arbetsmarknaden på planeten — och en av de svåraste att skrapa. Den öppna källkods-scrapern JobFunnel (tusentals GitHub-stjärnor) arkiverades bokstavligen av sin underhållare i december 2025 efter år av förlorad kapplöpning mot anti-bot-systemen. Underhållarens egna ord: "All users can scrape some jobs, but are quickly hit by captcha, and the scraping fails, yielding no jobs." En annan bidragsgivare rapporterade att de fick en CAPTCHA vid allra första begäran. Så ja — det här är inte ett trivialt skrapmål. I den här guiden går jag igenom varje praktisk metod för att skrapa Indeed med Python, visar hur du faktiskt överlever 403-hindret och demonstrerar — för den som helst hoppar över felsökningen helt — ett kodfritt alternativ med Thunderbit.

Vad betyder det att skrapa Indeed med Python?

Web scraping är i grunden automatiserad extraktion av strukturerad data från webbsidor. När vi talar om att skrapa Indeed med Python menar vi att skriva ett skript som besöker InDeeds sökresultat och jobbsidor, läser den underliggande HTML-koden (eller inbäddad data) och plockar ut fält som jobbtitel, företag, plats, lön och beskrivning i ett användbart format — en CSV, en databas eller ett Google Sheet.

De typiska Python-biblioteken som används är Requests (för HTTP-anrop), BeautifulSoup (för HTML-parsning) och Selenium eller Playwright (för webbläsarautomatisering). Men Indeed är inte en enkel statisk sajt. Den är en hybrid: serverrenderad HTML med ett inbäddat JSON-tillståndsobjekt, skyddad av Cloudflare Bot Management. Det betyder att din scraper behöver hantera JavaScript-renderat innehåll, roterande CSS-klassnamn och aggressivt anti-botskydd — allt innan du ens parserar en enda jobbtitel.

Det finns inte heller något officiellt, gratis, endast-läsbart Indeed-API 2026. Det gamla Publisher Jobs API:et togs ur bruk runt 2020, och det som återstår är endast för arbetsgivare (Job Sync, Sponsored Jobs). Så scraping eller att betala en tredjepartsdataleverantör är de enda realistiska alternativen.

Varför skrapa jobbdatan från Indeed?

Affärsnyttan med att skrapa Indeed är enkel: att manuellt gå igenom tusentals annonser är opraktiskt, och datan i annonserna är verkligen värdefull.

indeed_stats_dca2a43cec.png

AnvändningsområdeVem gynnasExempel
LeadgenereringSälj- och rekryteringsteamBygg listor över företag som anställer med kontaktuppgifter
Forskning om arbetsmarknadenAnalytiker, HR-teamIdentifiera trender i kompetenser och lönenivåer per region
KonkurrensbevakningArbetsgivare, bemanningsföretagFölj konkurrenters anställningsmönster och löneerbjudanden
Automatisering av personlig jobbsökningJobbsökareSamla annonser som matchar dina kriterier över olika platser
Träningsdata för ML-modellerData scientistsBygg modeller för löneprognoser från historisk data

InDeeds egen forskning i Hiring Lab bekräftar att annonsdata följer BLS JOLTS nära och kan fungera som en nästan realtidsproxy för läget på den amerikanska arbetsmarknaden. Hedgefonder använder förändringstakten i jobbannonser som en alternativ datasignal. HR-team jämför ersättning genom skrapade lönespann. Och rekryterare bygger prospektlistor från företag som aktivt anställer.

En praktisk notis: löneuppgifterna på Indeed blir bättre men är fortfarande ofullständiga. I mitten av 2025 innehöll ungefär 59 % av annonserna i USA löneinformation, men bara cirka 22 % angav en exakt siffra — resten var intervall. All lönedataanalys som bygger på Indeed-data bör ta hänsyn till den bristande täckningen.

Välj metod för att skrapa Indeed med Python

Det finns inget enda "rätt" sätt att skrapa Indeed. Den bästa metoden beror på din kunskapsnivå, hur mycket data du behöver och hur mycket underhåll du kan leva med. Jag har testat alla fyra huvudmetoderna, och så här står de sig mot varandra:

KriteriumBS4 + RequestsSeleniumDold JSON (window.mosaic)Kodfritt (Thunderbit)
SvårighetsgradNybörjareMedelnivåMedel–avanceradIngen (2 klick)
HastighetSnabbLångsam (webbläsarrendering)SnabbSnabb (molnskrapning)
JS-renderat innehållNejJaJa (inbäddad data)Ja
Motståndskraft mot anti-botLågMedel (kan upptäckas)Medel-högHög (hanteras automatiskt)
Underhåll när HTML ändrasHögt (selectors går sönder)HögtMedel (JSON-strukturen är stabilare)Inget (AI anpassar sig)
Bäst förSnabba prototyperDynamiska sidor, inloggningsskyddat innehållStrukturerad massdataIcke-utvecklare, snabba resultat

Den här guiden går igenom varje metod. Om du är Pythonutvecklare bör du läsa avsnitten om BS4, dold JSON och Selenium. Om du inte kodar — eller bara är trött på att felsöka 403-fel — hoppa vidare till Thunderbit-avsnittet.

Innan du börjar

  • Svårighetsgrad: Nybörjare till medelnivå (Python-avsnitt); ingen (Thunderbit-avsnitt)
  • Tidsåtgång: cirka 20–60 minuter för Python-setup och första skrapningen; cirka 2 minuter med Thunderbit
  • Det du behöver: Python 3.9+, en kodredigerare, Chrome och (för den kodfria vägen) Thunderbit Chrome Extension

Ställ in din Python-miljö för Indeed-scraping

Innan du skriver någon skrapkod, gör din miljö redo.

Installera nödvändiga bibliotek

Skapa en virtuell miljö och installera paketen du behöver:

python -m venv indeed_env
source indeed_env/bin/activate  # På Windows: indeed_env\Scripts\activate

# För HTTP + parsning
pip install requests beautifulsoup4 lxml httpx

# För metoden med dold JSON (rekommenderas)
pip install curl_cffi parsel tenacity

# För webbläsarautomatisering
pip install selenium

Några kommentarer:

  • curl_cffi är standardvalet 2026 för att skrapa sajter skyddade av Cloudflare. Det imiterar riktiga webbläsar-TLS-fingeravtryck, vilket vanliga requests och httpx inte kan göra. Mer om varför det spelar roll i anti-bot-avsnittet.
  • Selenium 4.6+ levereras med Selenium Manager, så du behöver inte längre ladda ner ChromeDriver manuellt — den hanterar webbläsarbinären automatiskt.
  • Använd lxml som parser-backend för BeautifulSoup. Den är ungefär 1,5 gånger snabbare än standardbibliotekets html.parser.

Skapa din projektstruktur

Håll det enkelt:

indeed_scraper/
├── scraper.py
├── requirements.txt
└── output/

Alla kodexempel nedan bygger vidare på scraper.py.

Hur du skrapar Indeed med Python med BeautifulSoup

Det här är nybörjarvänliga metoden: använd requests för att hämta sidan och BeautifulSoup för att parsa HTML-koden. Det går snabbast att sätta upp, men är också mest ömtåligt på Indeed.

Steg 1: Bygg Indeed-sök-URL:en

InDeeds sök-URL:er följer ett förutsägbart mönster:

https://www.indeed.com/jobs?q=<query>&l=<location>&start=<offset>

Till exempel, om du söker efter "data analyst" i "Austin, TX" med start från första sidan:

from urllib.parse import urlencode

params = {
    "q": "data analyst",
    "l": "Austin, TX",
    "start": 0,
}
url = f"https://www.indeed.com/jobs?{urlencode(params)}"
print(url)
# https://www.indeed.com/jobs?q=data+analyst&l=Austin%2C+TX&start=0

Indeed delar upp resultat i steg om 10, med ett hårt tak på 1 000 resultat (start <= 990). Alla offset-värden över 990 returnerar tyst samma sida.

Steg 2: Skicka en HTTP-begäran med rätt headers

Indeed blockerar direkt förfrågningar med standardiserade Python user-agent-strängar. Du behöver realistiska headers:

import requests

headers = {
    "User-Agent": (
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
        "(KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36"
    ),
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
    "Accept-Language": "en-US,en;q=0.9",
    "Accept-Encoding": "gzip, deflate, br",
    "Referer": "https://www.indeed.com/",
}

response = requests.get(url, headers=headers, timeout=30)
print(response.status_code)

Om du får 200 är du inne — för stunden. Om du får 403 har Cloudflare fångat dig. (Mer om hur du överlever det nedan.)

Steg 3: Parsea jobbannonser från HTML-koden

Använd BeautifulSoup för att välja jobbkortens element. Sikta på data-testid-attribut — de är stabilare än InDeeds slumpmässiga CSS-klassnamn:

from bs4 import BeautifulSoup

soup = BeautifulSoup(response.text, "lxml")
cards = soup.find_all("div", attrs={"data-testid": "slider_item"})

jobs = []
for card in cards:
    title_el = card.find("h2", class_="jobTitle")
    title = title_el.get_text(strip=True) if title_el else None
    company = card.find(attrs={"data-testid": "company-name"})
    location = card.find(attrs={"data-testid": "text-location"})
    link = title_el.find("a")["href"] if title_el and title_el.find("a") else None

    jobs.append({
        "title": title,
        "company": company.get_text(strip=True) if company else None,
        "location": location.get_text(strip=True) if location else None,
        "url": f"https://www.indeed.com{link}" if link else None,
    })

print(f"Hittade {len(jobs)} jobb")

Steg 4: Hantera paginering

Loopa genom sidorna genom att öka start-parametern:

import time, random

all_jobs = []
for page in range(0, 50, 10):  # Första 5 sidorna
    params["start"] = page
    url = f"https://www.indeed.com/jobs?{urlencode(params)}"
    response = requests.get(url, headers=headers, timeout=30)
    # ... parsa som ovan ...
    all_jobs.extend(jobs)
    time.sleep(random.uniform(3, 6))

Begränsningar med den här metoden

Jag ska vara rak: BS4 + Requests är den svagaste metoden för Indeed 2026. Vanliga requests använder Python standardbiblioteks TLS-bibliotek, vilket ger ett JA3-fingeravtryck som Cloudflare direkt identifierar som "inte en webbläsare." Det stöder heller inte HTTP/2, vilket Indeed levererar. Du kommer sannolikt att blockeras efter några få sidor. Och CSS-selectors? Indeed roterar klassnamn som css-1m4cuuf och jobsearch-JobComponent-embeddedBody-1n0gh5s ofta — så varje selector som riktar in sig på dem är en tickande bomb.

Använd den här metoden för snabba prototyper på en enda sida. För allt i större skala, använd metoden med dold JSON.

Hur du skrapar Indeed med Python med dold JSON-data

Det här är metoden jag rekommenderar för de flesta Pythonutvecklare. I stället för att parsa ömtåliga HTML-element extraherar du strukturerad data från en JavaScript-variabel inbäddad i InDeeds sidkälla: window.mosaic.providerData["mosaic-provider-jobcards"].

Varje fält du bryr dig om — jobbtitel, företag, plats, lön, jobbnymmer, publiceringsdatum, distansflagga — finns redan i detta JSON-objekt. Ingen JavaScript-exekvering krävs. Schemat har varit stabilt åtminstone sedan 2023, vilket gör det mycket mer motståndskraftigt än DOM-selectors.

Steg 1: Hämta sidans HTML

Använd curl_cffi i stället för requests — det imiterar riktiga webbläsar-TLS-fingeravtryck, vilket är avgörande för att överleva Cloudflare:

from curl_cffi import requests as cffi_requests

response = cffi_requests.get(
    "https://www.indeed.com/jobs?q=python+developer&l=Remote&start=0",
    impersonate="chrome124",
    headers={
        "Accept-Language": "en-US,en;q=0.9",
        "Referer": "https://www.indeed.com/",
    },
    timeout=30,
)
print(response.status_code, len(response.text))

Varför curl_cffi? Det är en Python-bindning ovanpå curl-impersonate, som återskapar exakt TLS ClientHello, HTTP/2 SETTINGS-ram och headerordning från riktiga webbläsare. Det är den enda aktivt underhållna Python-HTTP-klienten som slår ut både JA3/JA4 och Akamais H2-fingeravtryck i ett enda anrop. Stödda impersonation-mål inkluderar chrome120, chrome124, chrome131, Safari och Edge-varianter.

Steg 2: Extrahera JSON med ett reguljärt uttryck

JSON-blocket är inbäddat i en <script>-tagg. Plocka ut det med regex:

import re, json

MOSAIC_RE = re.compile(
    r'window\.mosaic\.providerData\["mosaic-provider-jobcards"\]=(\{.+?\});',
    re.DOTALL,
)

match = MOSAIC_RE.search(response.text)
if match:
    data = json.loads(match.group(1))
    results = data["metaData"]["mosaicProviderJobCardsModel"]["results"]
    print(f"Hittade {len(results)} jobb i den dolda JSON:en")
else:
    print("Dold JSON hittades inte — möjligt block eller sidändring")

Steg 3: Parsea jobbfält från JSON:en

Varje objekt i results innehåller mer data än det som syns på sidan:

jobs = []
for job in results:
    jobs.append({
        "jobkey": job["jobkey"],
        "title": job["title"],
        "company": job.get("company"),
        "location": job.get("formattedLocation"),
        "remote": job.get("remoteLocation"),
        "salary": (job.get("salarySnippet") or {}).get("text"),
        "posted": job.get("formattedRelativeTime"),
        "job_type": job.get("jobTypes"),
        "easy_apply": job.get("indeedApplyEnabled"),
        "url": f"https://www.indeed.com/viewjob?jk={job['jobkey']}",
    })

JSON:en innehåller ofta löneuppskattningar, taxonomiattribut (kompetens-taggar) och företagsbetyg som inte alltid syns i den renderade HTML-koden.

Steg 4: Skrapa flera sidor

Använd tierSummaries i JSON:en för att förstå totala resultatantal, och loopa sedan:

import time, random

all_jobs = []
for start in range(0, 50, 10):  # Första 5 sidorna
    url = f"https://www.indeed.com/jobs?q=python+developer&l=Remote&start={start}&sort=date"
    response = cffi_requests.get(
        url,
        impersonate="chrome124",
        headers={"Accept-Language": "en-US,en;q=0.9", "Referer": "https://www.indeed.com/"},
        timeout=30,
    )
    match = MOSAIC_RE.search(response.text)
    if match:
        data = json.loads(match.group(1))
        results = data["metaData"]["mosaicProviderJobCardsModel"]["results"]
        all_jobs.extend([{
            "jobkey": j["jobkey"],
            "title": j["title"],
            "company": j.get("company"),
            "location": j.get("formattedLocation"),
            "salary": (j.get("salarySnippet") or {}).get("text"),
            "url": f"https://www.indeed.com/viewjob?jk={j['jobkey']}",
        } for j in results])
    time.sleep(random.uniform(3, 7))

print(f"Totalt: {len(all_jobs)} jobb skrapade")

Varför dold JSON är mer robust

Strukturen window.mosaic.providerData ändras mer sällan än CSS-klassnamn. Du får ren, strukturerad data utan att behöva parsa rörig HTML. Med det sagt behöver du fortfarande anti-bot-mitigation (headers, fördröjningar, proxies) — vilket vi går igenom härnäst.

Hur du skrapar Indeed med Python med Selenium

Selenium är metoden för webbläsarautomatisering. Den är användbar när du behöver interagera med sidan — klicka in i jobbdetaljpaneler, hantera inloggningsskyddat innehåll eller skrapa dynamiskt laddade beskrivningar som inte finns i den initiala HTML-koden.

När du ska använda Selenium i stället för HTTP-klienter

  • Indeed laddar viss information dynamiskt (fullständiga jobbeskrivningar i panelen till höger)
  • Du behöver skrapa sidor som kräver sessionstillstånd eller inloggning
  • Du gör skrapning i liten skala där hastighet inte är avgörande

Snabb genomgång

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
import time

options = Options()
options.add_argument("--disable-blink-features=AutomationControlled")
# options.add_argument("--headless=new")  # Headless är mer upptäckbart — använd med försiktighet

driver = webdriver.Chrome(options=options)
driver.get("https://www.indeed.com/jobs?q=data+engineer&l=New+York")
time.sleep(3)

cards = driver.find_elements(By.CSS_SELECTOR, "[data-testid='slider_item']")
for card in cards:
    try:
        title = card.find_element(By.CSS_SELECTOR, "h2.jobTitle").text
        company = card.find_element(By.CSS_SELECTOR, "[data-testid='company-name']").text
        location = card.find_element(By.CSS_SELECTOR, "[data-testid='text-location']").text
        print(f"{title} | {company} | {location}")
    except Exception:
        continue

driver.quit()

Begränsningar

Selenium är långsamt — varje sida kräver fullständig webbläsarrendering. Headless Chrome är upptäckbart av InDeeds anti-bot-system (Cloudflare kontrollerar navigator.webdriver, WebGL-leverantörssträngar, antal plugins med mera). Även undetected-chromedriver fördröjer bara upptäckten; det förhindrar den inte permanent. Och precis som med BS4 kommer dina selectors att gå sönder när Indeed uppdaterar sitt gränssnitt.

För de flesta användningsfall ger metoden med dold JSON samma data snabbare och med mindre underhåll. Spara Selenium för edge cases där du verkligen behöver en webbläsare.

Hur du undviker 403-fel när du skrapar Indeed med Python

Det här är avsnittet som betyder mest. Om du har hamnat här via en frustrerad Google-sökning är du på rätt plats.

indeed_antibot_374d080ff4.png

Varför Indeed blockerar din scraper

Indeed använder Cloudflare Bot Management plus Cloudflare Turnstile — inte DataDome, inte PerimeterX. Svarshuvudena bekräftar det: server: cloudflare, cf-ray och bot-hanterings-cookien __cf_bm. Cloudflare granskar ditt TLS-fingeravtryck (JA3/JA4), ordningen på HTTP/2-headrar, förfrågemönster och signaler om webbläsarbeteende. Om något av detta ser icke-mänskligt ut får du en 403, 429, 503 eller — det lömskaste fallet — ett 200 OK med en Turnstile-utmaningssida i stället för riktig jobbinformation.

Rotera User-Agent och request-headers

En enda statisk User-Agent är det snabbaste sättet att bli blockerad. Rotera från en pool av aktuella, realistiska strängar. Viktigt: Chromes mindre versionsfält är frysta till 0.0.0 sedan User-Agent Reduction — hitta inte på icke-nollvärden för mindre versioner, annars flaggar anti-bot-systemen dem.

import random

USER_AGENTS = [
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
    "(KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 "
    "(KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
    "(KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36 Edg/145.0.3800.97",
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 "
    "(KHTML, like Gecko) Version/17.4 Safari/605.1.15",
]

headers = {
    "User-Agent": random.choice(USER_AGENTS),
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
    "Accept-Language": "en-US,en;q=0.9",
    "Accept-Encoding": "gzip, deflate, br, zstd",
    "Referer": "https://www.indeed.com/",
    "Sec-Fetch-Dest": "document",
    "Sec-Fetch-Mode": "navigate",
    "Sec-Fetch-Site": "same-origin",
}

Se också till att dina sec-ch-ua Client Hints matchar UA-versionen. En sec-ch-ua: "Chrome";v="131" bredvid en User-Agent som påstår Chrome 145 är en omedelbar varningssignal.

Lägg till slumpmässiga fördröjningar mellan begärningar

Fasta intervaller upptäcks av mönsterigenkänning. Använd slumpmässig jitter:

import time, random

# Mellan varje begäran
time.sleep(random.uniform(3, 6))

# Vid återförsök efter blockering
def backoff_sleep(attempt):
    base = 4
    sleep_time = base * (2 ** attempt) + random.uniform(0, 2)
    time.sleep(min(sleep_time, 60))

Branschens samlade erfarenhet från ScrapeOps och WebScraping.AI är 3–6 sekunder mellan begärningar per IP, med ett hårt tak på omkring 100 begärningar per IP och session innan du roterar.

Använd proxyrotation

Det här är den enskilt största faktorn för framgång. Datacenterproxies från AWS/GCP-områden når ungefär 5–15 % träffsäkerhet mot Cloudflare Enterprise-mål — praktiskt taget oanvändbart på Indeed. Residential proxies plus korrekt TLS-fingeravtryck kliver upp till 80–95 % träffsäkerhet.

PROXIES = [
    "http://user:pass@us.residential.example:7777",
    "http://user:pass@us.residential.example:7778",
    "http://user:pass@us.residential.example:7779",
]

proxy = random.choice(PROXIES)
response = cffi_requests.get(
    url,
    impersonate="chrome124",
    headers=headers,
    proxies={"https": proxy},
    timeout=30,
)

Priserna för residential proxies 2026 ligger ungefär på $4–8,50 per GB beroende på leverantör och åtagandenivå. För just Indeed, börja med en liten pool och skala upp vid behov.

Hantera statuskoderna 403, 429 och 503 på rätt sätt

Försök inte bara igen blint. Olika statuskoder betyder olika saker:

def fetch_with_retry(url, proxy_pool, max_retries=5):
    for attempt in range(max_retries):
        proxy = random.choice(proxy_pool)
        headers["User-Agent"] = random.choice(USER_AGENTS)
        try:
            r = cffi_requests.get(
                url,
                impersonate=random.choice(["chrome124", "chrome120", "edge101"]),
                headers=headers,
                proxies={"https": proxy},
                timeout=30,
            )
            # Kontrollera också det lömska fallet "200 med challenge"
            if r.status_code == 200 and "cf-turnstile" not in r.text and "Just a moment" not in r.text:
                return r

            if r.status_code == 403:
                print(f"403 — blockerad. Roterar proxy, försök {attempt + 1}")
            elif r.status_code == 429:
                print(f"429 — hastighetsbegränsad. Sakta ner.")
            elif r.status_code == 503:
                print(f"503 — servern är överbelastad eller så är det en JS-utmaning.")

            backoff_sleep(attempt)
        except Exception as e:
            print(f"Begäran misslyckades: {e}")
            backoff_sleep(attempt)

    raise RuntimeError(f"Misslyckades efter {max_retries} återförsök: {url}")

Fallet med 200-och-challenge är det knepigaste. Sök alltid igenom svarskroppen efter markörer som cf-turnstile eller Just a moment innan du behandlar ett 200 som framgång.

Det enklare alternativet: låt Thunderbit hantera anti-bot åt dig

För användare som inte vill bygga och underhålla proxy-pooler, headerrotation och TLS-fingeravtrycks-imitation hanterar Thunderbits molnskrapning CAPTCHAs, proxyrotation och anti-botskydd automatiskt. Ingen proxy-setup, ingen curl_cffi-konfiguration, inga bibliotek för CAPTCHA-lösning. Det är vägen med minst motstånd när du bara behöver datan.

Varför din Indeed-scraper hela tiden går sönder (och hur du fixar det)

403-väggen är den akuta smärtan. Den kroniska smärtan är underhåll — scrapers som fungerar idag går sönder nästa vecka och returnerar tyst tom data eller föråldrade resultat.

Hur Indeed bryter dina selectors

Indeed roterar CSS-klassnamn aggressivt. Bright Datas guide varnar uttryckligen för att klasser som css-1m4cuuf och css-1rqpxry "verkar vara slumpmässigt genererade — sannolikt vid byggtid." A/B-testning gör att olika sessioner ser olika sidlayouter. Och omstrukturering av DOM sker utan förvarning.

JobFunnel-historien är lärorik. En bidragsgivare rapporterade: "CaptchaBuster has successfully mitigated the captcha, and the reason for still unsuccessfully scraping the page [is] due to outdated beautiful soup selectors." Scrapen var inte blockerad — den parserade fel element.

Strategi: föredra dold JSON framför DOM-parsning

window.mosaic.providerData-blocket har haft ett stabilt schema åtminstone sedan 2023. Sökvägen metaData.mosaicProviderJobCardsModel.results[] är fortfarande den kanoniska 2026. DOM-selectors går sönder varje månad. JSON-extraktion går sönder årligen, om ens det.

Strategi: använd data-attribut i stället för klassnamn

När du väl måste röra DOM:en, rikta in dig på funktionella attribut:

SelectorSyfte
[data-testid="slider_item"]Behållaren för varje jobbkort
[data-testid="job-title"] eller h2.jobTitle > aLänk för jobbtitel
[data-testid="company-name"]Arbetsgivarens namn
[data-testid="text-location"]Platsfältet
data-jk="<jobkey>" på varje kortDen mest stabila kroken — oförändrad sedan 2019

Lägg till assertions för att upptäcka föråldrade selectors

Låt aldrig din scraper köras tyst med noll resultat. Lägg till en kontroll efter varje hämtning:

results = parse_hidden_json(html)
assert len(results) > 0, (
    f"Indeed returnerade en tom resultatuppsättning vid start={start} — "
    "möjligt block, CAPTCHA eller att selector-strukturen ändrats. "
    f"Första 500 tecken av svaret: {html[:500]}"
)

Logga de första 500–2000 tecknen av det råa svaret vid fel. Då kan du direkt se om du fick en Turnstile-utmaning, en inloggningsvägg eller ett schemafel. Kör ett dagligt CI-smoketest mot en fast sökning (t.ex. q=python&l=remote) som verifierar att resultatantalet är större än noll.

AI-alternativet: scrapers som aldrig går sönder

Thunderbits AI läser sidstrukturen på nytt varje gång — den förlitar sig inte på hårdkodade selectors eller regex-mönster. När Indeed ändrar sin HTML anpassar Thunderbit sig automatiskt. Det här adresserar direkt det underhållsarbete som forumanvändare konsekvent lyfter som sin största frustration. Om du någon gång vaknat till ett Slack-meddelande som säger "scrapern returnerar tomma rader igen" vet du värdet av att slippa fixa det.

Skrapa Indeed utan att skriva Python: det kodfria alternativet

Alla konkurrerande guider antar att du ska skriva Pythonkod. Men forumdatan berättar en annan historia. Användare säger saker som "it's just so difficult with constant bugs and errors" och vissa föreslår att man anlitar någon på Fiverr bara för att få fram datan. Om det låter som du är det här avsnittet din nödutgång.

Hur du skrapar Indeed med Thunderbit (steg för steg)

Steg 1: Installera Thunderbit Chrome Extension från Chrome Web Store. Det är gratis att börja med.

Steg 2: Navigera till en Indeed-resultatsida i din webbläsare — till exempel https://www.indeed.com/jobs?q=data+analyst&l=Austin%2C+TX.

Steg 3: Klicka på Thunderbit-ikonen i webbläsarens verktygsfält och klicka sedan på "AI Suggest Fields." Thunderbits AI skannar sidan och upptäcker automatiskt kolumner som Jobbtitel, Företag, Plats, Lön, Jobb-URL och Publiceringsdatum. Du kan granska och justera de föreslagna fälten — ta bort kolumner du inte behöver eller lägg till egna genom att beskriva vad du vill ha på vanlig engelska.

Steg 4: Klicka på "Skrapa." Thunderbit extraherar data från sidan och visar den i en strukturerad tabell. Du bör se rader med jobbannonser och de fält du har konfigurerat.

Berika med skrapning av undersidor

Efter att du skrapat resultatsidan klickar du på "Skrapa undersidor" så låter du Thunderbit besöka varje enskild jobbdetaljsida. Den hämtar fullständiga jobbeskrivningar, kvalifikationer, förmåner och ansökningslänkar — ingen extra konfiguration behövs. Det motsvarar att skriva en andra Python-scraper som besöker varje /viewjob?jk=<jobkey>-URL, fast det tar ett klick.

Hantera paginering automatiskt

Thunderbit hanterar InDeeds klickbaserade paginering automatiskt. Ingen manuell konstruktion av offset-URL:er eller pagineringsloopar behövs. Den klickar sig genom sidorna och samlar resultaten.

Exportera till dina favoritverktyg

Exportera skrapad data till CSV, Excel, Google Sheets, Airtable eller Notion — helt gratis. Du behöver inte skriva kod för csv.writer() eller pandas.to_csv().

När ska du använda Python respektive Thunderbit?

ScenarioBästa verktyget
Anpassade datapipelines, schemalagd automatisering via cron/AirflowPython
Integration i en större kodbasPython
Helt anpassad parserlogikPython
Enstaka research eller marknadsanalysThunderbit
Icke-tekniska teammedlemmar behöver dataThunderbit
Få fram data nu utan att felsöka 403-felThunderbit
Berikning av undersidor utan någon setupThunderbit

Tidsjämförelse: Python-setup + anti-bot-felsökning = timmar till dagar (särskilt första gången). Thunderbit = under 2 minuter för samma data. Jag säger inte att Python är fel — jag säger att det beror på vad du behöver.

Är det lagligt att skrapa Indeed? Det du behöver veta

Ingen av de topprankade guiderna om Indeed-scraping tar upp lagligheten, vilket är förvånande med tanke på hur ofta "Is scraping Indeed legal?" dyker upp i forum. Det här är inte juridisk rådgivning, men här är landskapet.

InDeeds användarvillkor

InDeeds användarvillkor (indeed.com/legal) innehåller inte något generellt förbud mot scraping. Det enda uttryckliga förbudet mot automatisering finns i avsnitt A.3.5, som förbjuder "use of any automation, scripting, or bots to automate the Indeed Apply process." Det är snävt avgränsat till ansökningsflödet, inte till passiv läsning av offentliga jobbannonser. InDeeds primära verktyg för enforcement är tekniska — Cloudflare-utmaningar, IP-blockeringar och device fingerprinting — inte domstolar.

Relevant rättspraxis

Det mest citerade amerikanska fallet är hiQ Labs v. LinkedIn. Den 9:e kretsen fastslog i april 2022 att scraping av offentligt tillgänglig data "likely does not violate the CFAA" (Computer Fraud and Abuse Act). Men hiQ bedömdes senare ansvarigt för kontraktsbrott eftersom dess anställda hade skapat falska LinkedIn-profiler och accepterat användarvillkoren.

Mer nyligen gav Meta v. Bright Data (N.D. Cal., jan 2024) ett ännu tydligare utslag. Domare Chen fastslog att Facebooks och Instagrams användarvillkor "do not bar logged-off scraping of public data." Meta drog frivilligt tillbaka de återstående anspråken månaden efter.

InDeeds robots.txt

InDeeds robots.txt förbjuder i stort sett /jobs/ och /job/ för standarden User-agent: *, men tillåter uttryckligen Googlebot och Bingbot att komma åt /viewjob? — de enskilda jobbdetaljsidorna. AI-träningscrawlers (GPTBot, CCBot, anthropic-ai) är hårt begränsade. robots.txt är inte juridiskt bindande i USA, men att respektera den är god praxis och ett tecken på god tro.

Praktiska riktlinjer för ansvarsfull scraping

  • Skrapa endast offentligt tillgänglig data — logga aldrig in, skapa aldrig falska konton
  • Respektera rate limits: 1 begäran var 3–6:e sekund per IP, låg samtidighet
  • Publicera inte om skrapad data som din egen jobbplattform
  • Använd datan för personlig eller intern research, inte för kommersiell vidareförsäljning utan tillstånd
  • Släng eller hasha PII som du inte behöver; sätt ett lagringstak för personnära data
  • Om du arbetar i stor skala eller i EU/Storbritannien, rådgör med jurist — GDPR:s transparenskrav i artikel 14 gäller skrapad persondata

Risknivån: automatisering av personlig jobbsökning ligger i den lägre delen. Kommersiell vidareförsäljning i stor skala av InDeeds data ligger i den högre delen.

Slutsats och viktiga lärdomar

Att skrapa Indeed med Python går att göra, men det är inte ett helgprojekt du ställer in och glömmer. InDeeds Cloudflare-skydd, roterande selectors och aggressiva anti-botåtgärder betyder att du behöver angripa detta med rätt verktyg och rätt förväntningar.

Här är vad jag skulle ta med mig från allt detta:

  • Indeed är den rikaste källan till data om arbetsmarknaden på webben — 350 miljoner besökare per månad, 130 miljoner annonser — men de slåss hårt mot scrapers.
  • Extraktion av dold JSON (window.mosaic.providerData) är den mest robusta Python-metoden. Schemat har varit stabilt i åratal, medan CSS-selectors går sönder varje månad.
  • curl_cffi med webbläsar-imitation är standard-HTTP-klienten 2026 för sajter skyddade av Cloudflare. Vanliga requests och httpx blockeras redan på TLS-fingeravtrycket.
  • Använd alltid roterande headers, slumpmässiga fördröjningar och residential proxies för att undvika 403-fel. Datacenterproxies är nästan värdelösa mot Cloudflare Enterprise.
  • Lägg till assertion-kontroller så du direkt ser när selectors går sönder eller när du serveras en utmaningssida i stället för jobbdatan.
  • För icke-tekniska användare eller alla som bara vill ha resultat snabbt erbjuder Thunderbit en kodfri, AI-driven väg som anpassar sig automatiskt när sajten ändras — inga proxies, ingen felsökning, inget underhåll.

Om du vill prova den kodfria vägen erbjuder Thunderbit en gratis nivå så att du kan testa på Indeed utan förbindelser. Och om du går Python-vägen är kodexemplen ovan en bra startpunkt — kom bara ihåg att behandla motståndskraft mot anti-bot som en förstklassig fråga, inte som något du tar tag i i efterhand.

För mer om web scraping-metoder och verktyg, kolla in våra guider om hur man skrapar webben med Python, bästa automatiserade web scraping-verktyg och web scraping utan att bli blockerad. Du kan också titta på tutorials på Thunderbit YouTube-kanal.

Prova Thunderbit för att skrapa Indeed-data snabbare Get Started Free

Vanliga frågor

Vilka Pythonbibliotek är bäst för att skrapa Indeed?

För HTTP-begärningar är curl_cffi det starkaste valet 2026 — det imiterar riktiga webbläsar-TLS-fingeravtryck, vilket är avgörande för att kringgå Cloudflare. httpx med HTTP/2 är ett okej alternativ för mindre skyddade mål. För HTML-parsning är BeautifulSoup4 med lxml fortfarande standard. För webbläsarautomatisering fungerar Playwright (med playwright-stealth) eller undetected-chromedriver, även om båda blir allt lättare att upptäcka. Metoden med regex över den dolda JSON:en (window.mosaic.providerData) gör att du slipper tung parsning helt.

Varför får jag hela tiden 403-fel när jag skrapar Indeed?

Indeed använder Cloudflare Bot Management, som granskar ditt TLS-fingeravtryck (JA3/JA4), ordningen på HTTP/2-headrar, förfrågemönster och webbläsarbeteende. Om du använder vanliga requests identifierar TLS-fingeravtrycket dig direkt som ett Python-skript — 403 kommer innan dina headers ens läses. Lös det genom att byta till curl_cffi med webbläsar-imitation, rotera realistiska User-Agent-strängar, lägga till slumpmässiga fördröjningar (3–6 sekunder) och använda residential proxies. Kontrollera också fallet med "200 med Turnstile-utmaning" — sök i svarskroppen efter markörer som cf-turnstile.

Kan jag skrapa Indeed utan att koda?

Ja. Verktyg som Thunderbit låter dig extrahera Indeed-jobbannonser på några klick — installera Chrome-tillägget, gå till en Indeed-söksida, klicka på "AI Suggest Fields" och sedan "Skrapa." Thunderbits AI identifierar automatiskt fält som jobbtitel, företag, plats och lön. Det hanterar paginering, berikning av undersidor (fullständiga jobbeskrivningar) och anti-botskydd automatiskt. Exportera till CSV, Google Sheets, Airtable eller Notion gratis.

Hur ofta ändrar Indeed sin HTML-struktur?

Indeed roterar regelbundet CSS-klassnamn (t.ex. css-1m4cuuf, slumpmässiga hashsträngar) och omstrukturerar DOM-element utan förvarning. A/B-testning gör att olika användare kan se olika layouter samtidigt. Metoden med dold JSON (window.mosaic.providerData) är betydligt stabilare — schemat har varit konsekvent sedan åtminstone 2023. När du måste använda DOM-selectors, rikta in dig på data-testid-attribut och data-jk (jobbnymmer) snarare än CSS-klasser.

Är det lagligt att skrapa Indeed?

Logged-out scraping av offentligt tillgängliga Indeed-URL:er för jobb bedöms sannolikt inte skapa CFAA-ansvar i USA, baserat på 9:e kretsens avgörande i hiQ v. LinkedIn (2022) och beslutet i Meta v. Bright Data (2024). InDeeds användarvillkor förbjuder specifikt att automatisera Apply-processen, inte passiv läsning av offentliga annonser. Med det sagt: skrapa alltid ansvarsfullt — logga inte in, skapa inga falska konton, respektera rate limits, publicera inte data som din egen jobbplattform och hantera personuppgifter (rekryterarnamn, e-postadresser) varsamt enligt GDPR/CCPA. För kommersiell verksamhet i större skala bör du rådgöra med jurist.

Läs mer

Fawad Khan
Fawad Khan
Fawad skriver för sitt levebröd, och ärligt talat tycker han ganska mycket om det. Han har ägnat år åt att ta reda på vad som gör en text rad att fastna — och vad som får läsare att scrolla vidare. Fråga honom om marknadsföring, så kan han prata i timmar. Fråga honom om carbonara, så pratar han ännu längre.
Innehåll

Samla in en webbsida genom att bara fråga

Säg vad du behöver på enkel engelska. Eller ännu bättre, säg ingenting alls.

Prova Thunderbit gratis
Extrahera data med AI
Överför enkelt data till Google Sheets, Airtable eller Notion
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week