Rundt den femtiende kopieringen og limingen av en stillingstittel fra Indeed inn i et regneark begynte jeg å stille spørsmål ved karrierevalgene mine. Hvis du noen gang har prøvd å hente strukturert data fra Indeed programmatisk, kjenner du allerede poenget: 403-feilen er ikke en bug — den er en del av Indeed sitt forsvarssystem.
Indeed er verdens største jobbportal, med omtrent 350 millioner unike besøkende i måneden, 130 millioner stillingsannonser til enhver tid og virksomhet i over 60 land. Det gjør den til en av de rikeste kildene til data om arbeidsmarkedet på kloden — og en av de vanskeligste å skrape. Den åpne skraperen JobFunnel (tusenvis av GitHub-stjerner) ble bokstavelig talt arkivert av vedlikeholderen i desember 2025 etter år med tapte kamper i anti-bot-racet. Vedlikeholderens egne ord: "All users can scrape some jobs, but are quickly hit by captcha, and the scraping fails, yielding no jobs." En annen bidragsyter rapporterte å få en CAPTCHA på aller første forespørsel. Så ja — dette er ikke et trivielt skrapemål. I denne guiden går jeg gjennom alle praktiske metoder for å skrape Indeed med Python, viser hvordan du faktisk kommer deg gjennom 403-terrengbanen, og demonstrerer — for dem som helst vil slippe feilsøking helt — et kodefritt alternativ med Thunderbit.
Hva betyr det å skrape Indeed med Python?
Web scraping er i bunn og grunn automatisk uthenting av strukturert data fra nettsider. Når vi snakker om å skrape Indeed med Python, mener vi å skrive et skript som besøker Indeed sine søkeresultater og stillingsdetaljsider, leser den underliggende HTML-en (eller innebygd data) og henter ut felt som stillingstittel, bedrift, sted, lønn og beskrivelse i et brukbart format — en CSV-fil, en database eller et Google Sheet.
De typiske Python-bibliotekene som brukes er Requests (for HTTP-kall), BeautifulSoup (for HTML-parsing) og Selenium eller Playwright (for nettleserautomatisering). Men Indeed er ikke et enkelt statisk nettsted. Det er en hybrid: serverrendert HTML med en innebygd JSON-statusblokk, frontet av Cloudflare Bot Management. Det betyr at skraperen din må håndtere JavaScript-rendret innhold, roterende CSS-klassenavn og aggressive anti-bot-beskyttelser — alt før du analyserer en eneste stillingstittel.
Det finnes heller ingen offisiell, gratis, skrivebeskyttet Indeed API i 2026. Den gamle Publisher Jobs API ble faset ut rundt 2020, og det som gjenstår er kun for arbeidsgivere (Job Sync, Sponsored Jobs). Dermed er scraping eller betaling til en tredjeparts dataleverandør de eneste realistiske alternativene.
Hvorfor skrape jobbdata fra Indeed?
Forretningscaset for å skrape Indeed er enkelt: manuell gjennomgang av tusenvis av annonser er upraktisk, og dataene i annonsene er genuint verdifulle.

| Bruksområde | Hvem har nytte av det | Eksempel |
|---|---|---|
| Leadgenerering | Salgs- og rekrutteringsteam | Bygg lister over bedrifter som ansetter, med kontaktinformasjon |
| Forskning på arbeidsmarkedet | Analytikere, HR-team | Identifiser trender i etterspurte ferdigheter og lønnsnivåer per region |
| Konkurranseanalyse | Arbeidsgivere, bemanningsbyråer | Følg med på konkurrenters ansettelsesmønstre og lønnstilbud |
| Automatisering av jobbsøk | Jobbsøkere | Samle annonser som matcher kriteriene dine på tvers av steder |
| Treningsdata for ML-modeller | Data scientists | Bygg lønnsprognosemodeller fra historiske data |
Indeed Hiring Labs egen forskning bekrefter at annonsedata følger BLS JOLTS tett og kan fungere som en nesten sanntidsindikator for arbeidsmarkedet i USA. Hedgefond bruker tempoet i stillingsutlysninger som et alternativt datasignal. HR-team bruker skrapede lønnsintervaller til å benchmarke kompensasjon. Og rekrutterere bygger prospektlister ut fra selskaper som faktisk ansetter.
En praktisk merknad: lønnsdata på Indeed blir bedre, men er fortsatt ufullstendig. Per midten av 2025 inkluderer omtrent 59 % av amerikanske annonser lønnsinformasjon, men bare rundt 22 % oppgir et eksakt beløp — resten er intervaller. Enhver lønnsanalyse basert på Indeed-data bør ta hensyn til denne mangelen.
Velg metode for å skrape Indeed med Python
Det finnes ikke én «riktig» måte å skrape Indeed på. Den beste metoden avhenger av ferdighetsnivået ditt, hvor mye data du trenger, og hvor mye vedlikehold du tåler. Jeg har testet alle fire hovedtilnærmingene, og slik står de seg mot hverandre:
| Kriterium | BS4 + Requests | Selenium | Skjult JSON (window.mosaic) | Kodefritt (Thunderbit) |
|---|---|---|---|---|
| Vanskelighetsgrad | Nybegynner | Middels | Middels–avansert | Ingen (2 klikk) |
| Hastighet | Rask | Langsom (nettleserrendering) | Rask | Rask (skybasert scraping) |
| JS-rendret innhold | Nei | Ja | Ja (innebygd data) | Ja |
| Motstand mot anti-bot | Lav | Middels (kan oppdages) | Middels–høy | Høy (håndteres automatisk) |
| Vedlikehold når HTML endres | Høyt (selectors ryker) | Høyt | Middels (JSON-strukturen er mer stabil) | Ingen (AI tilpasser seg) |
| Best for | Raske prototyper | Dynamiske sider, innloggingbeskyttet innhold | Strukturert data i bulk | Ikke-utviklere, raske resultater |
Denne guiden går gjennom hver metode. Hvis du er Python-utvikler, bør du lese seksjonene om BS4, skjult JSON og Selenium. Hvis du ikke koder — eller bare er lei av å feilsøke 403-feil — kan du hoppe videre til Thunderbit-delen.
Før du begynner
- Vanskelighetsgrad: Nybegynner til middels (Python-deler); ingen (Thunderbit-delen)
- Tidsbruk: ca. 20–60 minutter for Python-oppsett og første scraping; ca. 2 minutter med Thunderbit
- Du trenger: Python 3.9+, en kodeeditor, Chrome-nettleseren og (for kodefri vei) Thunderbit Chrome-utvidelsen
Sett opp Python-miljøet ditt for Indeed-scraping
Før du skriver noen scraping-kode, må du få miljøet klart.
Installer nødvendige biblioteker
Opprett et virtuelt miljø og installer pakkene du trenger:
python -m venv indeed_env
source indeed_env/bin/activate # På Windows: indeed_env\Scripts\activate
# For HTTP + parsing-tilnærmingen
pip install requests beautifulsoup4 lxml httpx
# For tilnærmingen med skjult JSON (anbefalt)
pip install curl_cffi parsel tenacity
# For nettleserautomatisering
pip install selenium
Noen merknader:
curl_cffier standardvalget i 2026 for scraping av nettsteder beskyttet av Cloudflare. Det etterligner ekte nettleser-TLS-fingeravtrykk, noe vanligerequestsoghttpxikke klarer. Mer om hvorfor dette betyr noe i anti-bot-delen.- Selenium 4.6+ leveres med Selenium Manager, så du trenger ikke lenger laste ned ChromeDriver manuelt — den håndterer nettleserbinæren automatisk.
- Bruk
lxmlsom parser-backend for BeautifulSoup. Den er omtrent 1,5 ganger raskere enn standardbiblioteketshtml.parser.
Lag prosjektstrukturen din
Hold det enkelt:
indeed_scraper/
├── scraper.py
├── requirements.txt
└── output/
Alle kodeeksemplene nedenfor bygger på scraper.py.
Slik skraper du Indeed med Python ved hjelp av BeautifulSoup
Dette er den nybegynnervennlige tilnærmingen: bruk requests til å hente siden og BeautifulSoup til å parse HTML-en. Den er raskest å sette opp, men også den mest skjøre på Indeed.
Trinn 1: Bygg Indeed-søke-URL-en
Indeed sine søke-URL-er følger et forutsigbart mønster:
https://www.indeed.com/jobs?q=<query>&l=<location>&start=<offset>
For eksempel, søk etter «data analyst» i «Austin, TX» fra første side:
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 paginerer i steg på 10, med en hard grense på 1 000 resultater (start <= 990). Enhver offset over 990 returnerer stille samme side.
Trinn 2: Send en HTTP-forespørsel med riktige headere
Indeed blokkerer forespørsler med standard Python user-agent-strenger umiddelbart. Du trenger realistiske headere:
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)
Hvis du får 200, er du inne — foreløpig. Hvis du får 403, har Cloudflare fanget deg. (Mer om hvordan du kommer deg gjennom det nedenfor.)
Trinn 3: Parse stillingsannonsene fra HTML-en
Bruk BeautifulSoup til å velge jobbkort-elementene. Sikt deg inn på data-testid-attributter — de er mer stabile enn Indeed sine tilfeldige CSS-klassenavn:
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"Fant {len(jobs)} jobber")
Trinn 4: Håndter paginering
Loop gjennom sider ved å øke start-parameteren:
import time, random
all_jobs = []
for page in range(0, 50, 10): # Første 5 sider
params["start"] = page
url = f"https://www.indeed.com/jobs?{urlencode(params)}"
response = requests.get(url, headers=headers, timeout=30)
# ... parse som over ...
all_jobs.extend(jobs)
time.sleep(random.uniform(3, 6))
Begrensninger ved denne tilnærmingen
Jeg er ærlig: BS4 + Requests er den svakeste metoden for Indeed i 2026. Vanlige requests bruker Python sitt TLS-bibliotek i standardbiblioteket, som produserer et JA3-fingeravtrykk som Cloudflare umiddelbart identifiserer som «ikke en nettleser». Det støtter heller ikke HTTP/2, som Indeed leverer. Du blir sannsynligvis blokkert etter noen få sider. Og CSS-selectorene? Indeed roterer klassenavn som css-1m4cuuf og jobsearch-JobComponent-embeddedBody-1n0gh5s ofte — så enhver selector som er avhengig av dem er en tikkende bombe.
Bruk denne metoden for rask prototyping på én enkelt side. For alt som skal skaleres, bruk tilnærmingen med skjult JSON.
Slik skraper du Indeed med Python ved hjelp av skjulte JSON-data
Dette er metoden jeg anbefaler for de fleste Python-utviklere. I stedet for å parse skjøre HTML-elementer, henter du strukturert data fra en JavaScript-variabel som er innebygd i kildekoden til Indeed: window.mosaic.providerData["mosaic-provider-jobcards"].
Hvert felt du bryr deg om — stillingstittel, bedrift, sted, lønn, jobb-nøkkel, publiseringsdato, fjernarbeidsflagg — finnes allerede i denne JSON-blokken. Ingen JavaScript-eksekvering kreves. Skjemaet har vært stabilt siden minst 2023, og det gjør det langt mer robust enn DOM-selectorer.
Trinn 1: Hent side-HTML-en
Bruk curl_cffi i stedet for requests — det etterligner ekte nettleser-TLS-fingeravtrykk, noe som er avgjørende for å overleve 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))
Hvorfor curl_cffi? Det er en Python-binding over curl-impersonate, som gjenskaper nøyaktig TLS ClientHello, HTTP/2 SETTINGS-rammen og header-rekkefølgen til ekte nettlesere. Det er den eneste aktivt vedlikeholdte Python HTTP-klienten som beseirer både JA3/JA4 og Akamai H2-fingeravtrykket i ett og samme kall. Støttede impersonation-mål inkluderer chrome120, chrome124, chrome131, Safari og Edge-varianter.
Trinn 2: Hent ut JSON-en med et regulært uttrykk
JSON-blokken er innebygd i en <script>-tagg. Hent den ut 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"Fant {len(results)} jobber i skjult JSON")
else:
print("Skjult JSON ble ikke funnet — mulig blokkering eller sideendring")
Trinn 3: Parse jobbfeltene fra JSON-en
Hvert element i results inneholder mer data enn det som er synlig på siden:
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 inneholder ofte lønnsestimater, taksonomi-attributter (ferdighetstags) og bedriftsvurderinger som ikke alltid er synlige i den rendrerte HTML-en.
Trinn 4: Skrap flere sider
Bruk tierSummaries i JSON-en for å forstå totalantallet resultater, og looper deretter:
import time, random
all_jobs = []
for start in range(0, 50, 10): # Første 5 sider
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)} jobber skrapet")
Hvorfor skjult JSON er mer robust
Strukturen window.mosaic.providerData endres sjeldnere enn CSS-klassenavn. Du får rene, strukturerte data uten å parse rotete HTML. Når det er sagt, må du fortsatt ha anti-bot-tiltak (headere, forsinkelser, proxyer) — det dekker vi neste.
Slik skraper du Indeed med Python ved hjelp av Selenium
Selenium er tilnærmingen med nettleserautomatisering. Den er nyttig når du må interagere med siden — klikke deg inn i jobbdetaljpaneler, håndtere innloggingsbeskyttet innhold eller skrape dynamisk lastede beskrivelser som ikke ligger i den første HTML-en.
Når du bør bruke Selenium i stedet for HTTP-klienter
- Indeed laster noe innhold dynamisk (fulle jobbtekster i høyrepanelet)
- Du må skrape sider som krever sesjonstilstand eller innlogging
- Du gjør scraping i liten skala der hastighet ikke er kritisk
Kjapp gjennomgang
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 er lettere å oppdage — bruk med forsiktighet
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()
Begrensninger
Selenium er tregt — hver side krever full nettleserrendering. Headless Chrome er detekterbart av Indeed sitt anti-bot-system (Cloudflare sjekker navigator.webdriver, WebGL-vendor-strenger, antall plugins og mer). Selv undetected-chromedriver utsetter bare oppdagelsen; det hindrer den ikke permanent. Og som med BS4 vil selectorene dine knekke når Indeed oppdaterer brukergrensesnittet sitt.
For de fleste bruksområder gir tilnærmingen med skjult JSON de samme dataene raskere og med mindre vedlikehold. Spar Selenium til spesialtilfeller der du faktisk trenger en nettleser.
Slik unngår du 403-feil når du skraper Indeed med Python
Dette er seksjonen som betyr mest. Hvis du kom hit via et frustrert Google-søk, er du på rett sted.

Hvorfor Indeed blokkerer skraperen din
Indeed bruker Cloudflare Bot Management pluss Cloudflare Turnstile — ikke DataDome, ikke PerimeterX. Responsheaderne bekrefter det: server: cloudflare, cf-ray og bot-management-cookien __cf_bm. Cloudflare inspiserer TLS-fingeravtrykket ditt (JA3/JA4), rekkefølgen på HTTP/2-headere, forespørselsmønstre og signaler for nettleseratferd. Hvis noe av dette ser ikke-menneskelig ut, får du 403, 429, 503 eller — den snikeste varianten — en 200 OK med en Turnstile-utfordringssiden i stedet for ekte jobbdata.
Roter User-Agent og forespørselsheadere
Én statisk User-Agent er den raskeste veien til blokkering. Roter fra en pool av aktuelle, realistiske strenger. Viktig: mindre versjonsfelter i Chrome er låst til 0.0.0 siden User-Agent Reduction — ikke finn på ikke-null mindre versjoner, ellers vil anti-boter flagge det.
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",
}
Sørg også for at sec-ch-ua Client Hints stemmer med UA-versjonen. En sec-ch-ua: "Chrome";v="131" ved siden av en User-Agent som hevder Chrome 145, er et rødt flagg med en gang.
Legg inn tilfeldige forsinkelser mellom forespørsler
Faste intervaller blir fanget opp av mønstergjenkjenning. Bruk tilfeldig jitter:
import time, random
# Mellom hver forespørsel
time.sleep(random.uniform(3, 6))
# Ved retry etter blokkering
def backoff_sleep(attempt):
base = 4
sleep_time = base * (2 ** attempt) + random.uniform(0, 2)
time.sleep(min(sleep_time, 60))
Konsensus fra ScrapeOps og WebScraping.AI er 3–6 sekunder mellom forespørsler per IP, med en hard grense på rundt 100 forespørsler per IP per økt før du roterer.
Bruk proxy-rotasjon
Dette er den klart viktigste faktoren for suksess. Datasenterproxyer fra AWS/GCP-områder gir omtrent 5–15 % suksessrate mot Cloudflare Enterprise-mål — i praksis ubrukelig på Indeed. Residential proxies kombinert med riktig TLS-fingeravtrykk øker sjansen til 80–95 %.
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,
)
Prisen på residential proxies i 2026 ligger omtrent på $4–8,50 per GB, avhengig av leverandør og forpliktelsesnivå. For Indeed bør du starte med en liten pool og skalere ved behov.
Håndter 403-, 429- og 503-statuskoder på en ryddig måte
Ikke bare prøv igjen blindt. Ulike statuskoder betyr ulike ting:
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,
)
# Sjekk for den snikete "200 med challenge"-varianten
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 — blokkert. Roterer proxy, forsøk {attempt + 1}")
elif r.status_code == 429:
print(f"429 — rate limit. Saktere tempo.")
elif r.status_code == 503:
print(f"503 — serveren er overbelastet eller JS-challenge.")
backoff_sleep(attempt)
except Exception as e:
print(f"Forespørselsfeil: {e}")
backoff_sleep(attempt)
raise RuntimeError(f"Mislyktes etter {max_retries} forsøk: {url}")
200-med-challenge-tilfellet er det vanskeligste. Sjekk alltid responsinnholdet for cf-turnstile eller Just a moment før du behandler en 200 som suksess.
Det enklere alternativet: la Thunderbit håndtere anti-bot for deg
For brukere som ikke vil bygge og vedlikeholde proxy-pooler, headerrotasjon og TLS-fingeravtrykks-impersonering, håndterer Thunderbit sin skybaserte scraping CAPTCHA-er, proxy-rotasjon og anti-bot-beskyttelse automatisk. Ingen proxy-oppsett, ingen curl_cffi-konfigurasjon, ingen CAPTCHA-løsningsbiblioteker. Det er minste motstands vei når du bare trenger dataene.
Hvorfor Indeed-skraperen din fortsetter å knekke (og hvordan fikse det)
403-veggen er den akutte smerten. Den kroniske smerten er vedlikehold — skrapere som virker i dag, ryker neste uke og returnerer stille tomme data eller utdaterte resultater.
Hvordan Indeed bryter selectorene dine
Indeed roterer CSS-klassenavn aggressivt. Bright Datas guide advarer eksplisitt om at klasser som css-1m4cuuf og css-1rqpxry «ser ut til å være tilfeldig generert — sannsynligvis ved bygging». A/B-testing gjør at ulike sesjoner ser ulike sidelayouts. Og DOM-omstrukturering skjer uten varsel.
JobFunnel-historien er opplysende. En bidragsyter rapporterte: "CaptchaBuster has successfully mitigated the captcha, and the reason for still unsuccessfully scraping the page [is] due to outdated beautiful soup selectors." Skraperen var ikke blokkert — den hentet bare feil elementer.
Strategi: Foretrekk skjult JSON fremfor DOM-parsing
Blokken window.mosaic.providerData har hatt stabilt skjema siden minst 2023. Stien metaData.mosaicProviderJobCardsModel.results[] er fortsatt den kanoniske i 2026. DOM-selectorer ryker månedlig. JSON-uttrekk ryker årlig, om i det hele tatt.
Strategi: Bruk data-attributter i stedet for klassenavn
Når du faktisk må bruke DOM-en, sikt mot funksjonelle attributter:
| Selector | Formål |
|---|---|
[data-testid="slider_item"] | Beholderen for hvert jobbkort |
[data-testid="job-title"] eller h2.jobTitle > a | Lenken for stillingstittelen |
[data-testid="company-name"] | Navn på arbeidsgiver |
[data-testid="text-location"] | Stedstekst |
data-jk="<jobkey>" på hvert kort | Den mest stabile kroken — uendret siden 2019 |
Legg inn assertions for å oppdage utdaterte selectorer
La aldri skraperen kjøre stille med null resultater. Legg inn en sjekk etter hver henting:
results = parse_hidden_json(html)
assert len(results) > 0, (
f"Indeed returnerte et tomt resultatsett ved start={start} — "
"mulig blokkering, CAPTCHA eller selector-drift. "
f"De første 500 tegnene av responsen: {html[:500]}"
)
Logg de første 500–2000 tegnene av råresponsen ved feil. Da ser du med en gang om du fikk en Turnstile-utfordring, en innloggingsvegg eller en skjemaendring. Kjør en daglig smoke test på CI-nivå mot et fast søk (for eksempel q=python&l=remote) som bekrefter at resultatene ikke er null.
AI-alternativet: skrapere som aldri bryter sammen
Thunderbit sin AI leser sidens struktur på nytt hver gang — den er ikke avhengig av hardkodede selectorer eller regex-mønstre. Når Indeed endrer HTML-en sin, tilpasser Thunderbit seg automatisk. Dette løser direkte vedlikeholdsbyrden som forumbrukere stadig nevner som den største frustrasjonen. Hvis du noen gang har våknet til en Slack-melding som sier «skraperen returnerer tomme rader igjen», vet du verdien av å slippe å fikse det selv.
Skrap Indeed uten å skrive Python: det kodefrie alternativet
Hver konkurrerende guide antar at du skal skrive Python-kode. Men forumdataene forteller en annen historie. Brukere sier ting som "it's just so difficult with constant bugs and errors" og noen foreslår å leie inn noen på Fiverr bare for å få dataene. Hvis det høres ut som deg, er denne delen nødluka di.
Slik skraper du Indeed med Thunderbit (trinn for trinn)
Trinn 1: Installer Thunderbit Chrome-utvidelsen fra Chrome Nettmarked. Den er gratis å komme i gang med.
Trinn 2: Gå til en Indeed-søkeresultatside i nettleseren — for eksempel https://www.indeed.com/jobs?q=data+analyst&l=Austin%2C+TX.
Trinn 3: Klikk på Thunderbit-ikonet i verktøylinjen, og klikk deretter "AI Suggest Fields." Thunderbit sin AI skanner siden og oppdager automatisk kolonner som Jobbtittel, Bedrift, Sted, Lønn, Jobb-URL og Publiseringsdato. Du kan gå gjennom og justere de foreslåtte feltene — fjerne kolonner du ikke trenger, eller legge til egne ved å beskrive hva du vil ha med vanlig språk.
Trinn 4: Klikk "Scrape." Thunderbit henter data fra siden og viser det i en strukturert tabell. Du skal se rader med stillingsannonser og feltene du har satt opp.
Berik med scraping av undersider
Etter at du har skrapet oppføringssiden, klikker du "Scrape Subpages" for å la Thunderbit besøke hver enkelt stillingsdetaljside. Den henter full jobbtekst, kvalifikasjoner, fordeler og søknadslenker — uten ekstra oppsett. Dette tilsvarer å skrive en ny Python-skraper som besøker hver /viewjob?jk=<jobkey>-URL, bare med ett klikk.
Håndter paginering automatisk
Thunderbit håndterer Indeed sin klikkbaserte paginering automatisk. Du slipper å konstruere offset-URL-er manuelt eller skrive pagineringsløkker. Den klikker seg gjennom sidene og samler resultatene.
Eksporter til favorittverktøyene dine
Eksporter skrapede data til CSV, Excel, Google Sheets, Airtable eller Notion — helt gratis. Du slipper å skrive kode med csv.writer() eller pandas.to_csv().
Når bør du bruke Python vs. Thunderbit
| Scenario | Beste verktøy |
|---|---|
| Egendefinerte datapipelines, planlagt automatisering via cron/Airflow | Python |
| Integrasjon i en større kodebase | Python |
| Høyst tilpasset parse-logikk | Python |
| Engangsundersøkelser eller markedsanalyse | Thunderbit |
| Ikke-tekniske teammedlemmer trenger data | Thunderbit |
| Få data nå uten å feilsøke 403-feil | Thunderbit |
| Berikelse av undersider uten oppsett | Thunderbit |
Tidsmessig sammenligning: Python-oppsett + anti-bot-feilsøking = timer til dager (særlig første gang). Thunderbit = under 2 minutter for samme data. Jeg sier ikke at Python er feil — jeg sier at det avhenger av hva du trenger.
Er det lovlig å skrape Indeed? Hva du bør vite
Ingen av de mest rangerte guidene om Indeed-scraping tar opp lovlighet, noe som er overraskende gitt hvor ofte "Is scraping Indeed legal?" dukker opp i forum. Dette er ikke juridisk rådgivning, men her er landskapet.
Indeed sine bruksvilkår
Indeed sine vilkår (indeed.com/legal) inneholder ikke en generell «ingen scraping»-klausul. Det eneste eksplisitte forbudet mot automatisering er i seksjon A.3.5, som forbyr "use of any automation, scripting, or bots to automate the Indeed Apply process." Det er smalt avgrenset til søknadsflyten, ikke passiv lesing av offentlige stillingsannonser. Indeed sitt primære håndhevingsverktøy er teknisk — Cloudflare-utfordringer, IP-blokkering, device fingerprinting — ikke rettssalen.
Relevant rettspraksis
Den mest siterte amerikanske saken er hiQ Labs v. LinkedIn. Den 9. kretsen fastslo i april 2022 at scraping av offentlig tilgjengelige data «sannsynligvis ikke bryter CFAA» (Computer Fraud and Abuse Act). hiQ ble likevel senere funnet ansvarlig for kontraktsbrudd fordi ansatte hadde opprettet falske LinkedIn-profiler og akseptert vilkårene.
Mer nylig ga Meta v. Bright Data (N.D. Cal., jan. 2024) en enda tydeligere avgjørelse. Dommer Chen fastslo at Facebooks og Instagrams vilkår «ikke forbyr utlogget scraping av offentlige data». Meta trakk de gjenværende kravene frivillig måneden etter.
Indeed sin robots.txt
Indeed sin robots.txt forbyr i stor grad /jobs/ og /job/ for standard User-agent: *, men tillater eksplisitt Googlebot og Bingbot tilgang til /viewjob? — de enkelte jobbdetaljsidene. AI-treningscrawlers (GPTBot, CCBot, anthropic-ai) er strengt begrenset. robots.txt er ikke juridisk bindende i USA, men å respektere den er god praksis og viser god tro.
Praktiske retningslinjer for ansvarlig scraping
- Skrap bare offentlig tilgjengelige data — aldri logg inn, aldri opprett falske kontoer
- Respekter rate limits: 1 forespørsel hvert 3.–6. sekund per IP, lav samtidighet
- Ikke republiser skrapet data som din egen jobbportal
- Bruk data til personlig eller intern analyse, ikke kommersiell videresalg uten tillatelse
- Slett eller hash PII du ikke trenger; sett en øvre grense for lagring av personnære data
- Hvis du opererer i stor skala eller i EU/Storbritannia, snakk med en advokat — GDPR artikkel 14s krav til åpenhet gjelder for skrapede personopplysninger
Risikospekteret: automatisering av personlig jobbsøk ligger i den lave enden. Stor-skala kommersiell videresalg av Indeed-data ligger i den høye.
Konklusjon og viktigste læringspunkter
Å skrape Indeed med Python er fullt mulig, men det er ikke et helgeprosjekt du setter opp og glemmer. Indeed sin Cloudflare-beskyttelse, roterende selectorer og aggressive anti-bot-tiltak betyr at du må gå til verks med riktige verktøy og riktige forventninger.
Dette er det jeg ville tatt med meg:
- Indeed er den rikeste kilden til data om arbeidsmarkedet på nettet — 350 millioner månedlige besøkende, 130 millioner annonser — men de kjemper hardt mot skrapere.
- Uttrekk av skjult JSON (
window.mosaic.providerData) er den mest robuste Python-tilnærmingen. Skjemaet har vært stabilt i årevis, mens CSS-selectorer ryker månedlig. curl_cffimed nettleser-impersonering er standard HTTP-klient i 2026 for nettsteder beskyttet av Cloudflare. Vanligerequestsoghttpxblir blokkert på grunn av TLS-fingeravtrykket alene.- Bruk alltid roterende headere, tilfeldige forsinkelser og residential proxies for å unngå 403-feil. Datasenterproxyer er nesten ubrukelige mot Cloudflare Enterprise.
- Legg inn assertion-sjekker slik at du umiddelbart ser når selectorer ryker eller når du får en utfordringssiden i stedet for jobbdata.
- For ikke-tekniske brukere eller alle som bare vil ha resultater raskt, gir Thunderbit en kodefri, AI-drevet vei som tilpasser seg endringer på nettstedet automatisk — ingen proxyer, ingen feilsøking, intet vedlikehold.
Hvis du vil prøve den kodefrie veien, tilbyr Thunderbit en gratis plan, så du kan teste den på Indeed uten forpliktelser. Og hvis du går Python-veien, er kodeeksemplene over et solid utgangspunkt — bare husk å behandle anti-bot-robusthet som et hovedhensyn, ikke en ettertanke.
For mer om web scraping-tilnærminger og verktøy, sjekk ut guidene våre om hvordan du skraper nettsider med Python, beste automatiserte web scraping-verktøy og web scraping uten å bli blokkert. Du kan også se veiledninger på Thunderbit YouTube-kanalen.
Prøv Thunderbit for å skrape Indeed-data raskere Get Started Free
Vanlige spørsmål
Hvilke Python-biblioteker er best for å skrape Indeed?
For HTTP-forespørsler er curl_cffi det sterkeste valget i 2026 — det etterligner ekte nettleser-TLS-fingeravtrykk, noe som er avgjørende for å komme forbi Cloudflare. httpx med HTTP/2 er et greit alternativ for mindre beskyttede mål. For HTML-parsing er BeautifulSoup4 med lxml fortsatt standarden. For nettleserautomatisering fungerer Playwright (med playwright-stealth) eller undetected-chromedriver, men begge blir i økende grad oppdaget. Den skjulte JSON-metoden med regex (window.mosaic.providerData) gjør tung parsing unødvendig.
Hvorfor får jeg stadig 403-feil når jeg skraper Indeed?
Indeed bruker Cloudflare Bot Management, som inspiserer TLS-fingeravtrykket ditt (JA3/JA4), rekkefølgen på HTTP/2-headere, forespørselsmønstre og nettleseratferd. Hvis du bruker vanlige requests, avslører TLS-fingeravtrykket umiddelbart at du er et Python-skript — 403 kommer før headerne dine engang blir lest. Løs det ved å bytte til curl_cffi med nettleser-impersonering, rotere realistiske User-Agent-strenger, legge inn tilfeldige forsinkelser (3–6 sekunder) og bruke residential proxies. Sjekk også for tilfeller med «200 og Turnstile-challenge» — søk i responskroppen etter cf-turnstile-markører.
Kan jeg skrape Indeed uten å kode?
Ja. Verktøy som Thunderbit lar deg hente ut stillingsannonser fra Indeed med noen få klikk — installer Chrome-utvidelsen, gå til en Indeed-søkeside, klikk «AI Suggest Fields», og deretter «Scrape». Thunderbit sin AI oppdager automatisk felt som stillingstittel, bedrift, sted og lønn. Den håndterer paginering, berikelse av undersider (fulle jobbtekster) og anti-bot-beskyttelse automatisk. Eksporter til CSV, Google Sheets, Airtable eller Notion gratis.
Hvor ofte endrer Indeed HTML-strukturen sin?
Indeed roterer jevnlig CSS-klassenavn (for eksempel css-1m4cuuf, tilfeldig genererte hashede strenger) og omstrukturerer DOM-elementer uten varsel. A/B-testing betyr at ulike brukere kan se ulike layouts samtidig. Tilnærmingen med skjult JSON (window.mosaic.providerData) er betydelig mer stabil — skjemaet har vært konsistent siden minst 2023. Når du må bruke DOM-selectorer, bør du sikte mot data-testid-attributter og data-jk (jobb-nøkkel) i stedet for CSS-klasser.
Er det lovlig å skrape Indeed?
Utlogget scraping av offentlig tilgjengelige Indeed-URL-er vil trolig ikke utløse CFAA-ansvar i USA, basert på den 9. kretsens avgjørelse i hiQ v. LinkedIn (2022) og Meta v. Bright Data-avgjørelsen (2024). Indeed sine vilkår forbyr spesifikt automatisering av søknadsprosessen, ikke passiv lesing av offentlige annonser. Når det er sagt: skrap ansvarlig — ikke logg inn, ikke opprett falske kontoer, respekter rate limits, ikke republiser data som din egen jobbportal, og håndter eventuelle personopplysninger (rekrutterernavn, e-poster) forsiktig i tråd med GDPR/CCPA. For kommersiell drift i stor skala bør du rådføre deg med en advokat.
Les mer


