Jak zeskrobać ogłoszenia o pracę z Indeed: Struktura, Bloki i Trasa SERP
Indeed to największa tablica ogłoszeń o pracę w sieci i sygnał rynku pracy na żywo. Jest również chroniona przez Cloudflare z nazwami klas, które zmieniają się co tydzień. Oto jak trwale je wyodrębnić — i kiedy całkowicie pominąć tę stronę.
Indeed przyciąga około 542 milionów wizyt miesięcznie, co czyni jego listy jednym z najczystszych sygnałów na żywo dla rynku pracy — popyt na zatrudnienie według roli, przedziały wynagrodzeń, które firmy zwiększają zatrudnienie. Jest to również chroniona przez Cloudflare strona React, której widoczne nazwy klas CSS zmieniają się wystarczająco często, by złamać naiwny scraper w ciągu kilku tygodni. Ten przewodnik pokazuje, jak trwale zeskrobać ogłoszenia o pracę z Indeed, jak je paginować i deduplikować, rzeczywistość Cloudflare i pion SERP z ofertami pracy, który pozwala całkowicie uniknąć walki.
Przeczytaj stronę wyników wyszukiwania, zakotwicz na stabilnych atrybutach
Jednostką danych Indeed jest strona wyników wyszukiwania: zapytanie plus lokalizacja daje stronę z kartami ofert pracy. Pułapką jest wybór na podstawie zhaszowanych nazw klas (takich jak eu4oa1w0), które Indeed regeneruje. Zamiast tego zakotwicz na atrybutach data-testid, które zmieniają się znacznie rzadziej:
import requests
from bs4 import BeautifulSoup
headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36",
"Accept-Language": "en-US,en;q=0.9",
}
proxies = {"http": "http://USER:PASS@gate.quantumproxies.io:8000",
"https": "http://USER:PASS@gate.quantumproxies.io:8000"}
url = "https://www.indeed.com/jobs?q=python&l=New+York%2C+NY"
html = requests.get(url, headers=headers, proxies=proxies, timeout=30).text
soup = BeautifulSoup(html, "html.parser")
jobs = []
for card in soup.select("div.job_seen_beacon"):
title = card.find("a", class_="jcs-JobTitle")
company = card.find("span", attrs={"data-testid": "company-name"})
location = card.find("div", attrs={"data-testid": "text-location"})
jobs.append({
"title": title.get_text(strip=True) if title else None,
"company": company.get_text(strip=True) if company else None,
"location": location.get_text(strip=True) if location else None,
"jk": title["href"].split("jk=")[-1][:16] if title else None,
})
print(len(jobs), "jobs on page 1")
Każda karta zawiera klucz pracy (jk) — stabilny identyfikator, którego używasz do deduplikacji między stronami i uruchomieniami. Przechowuj na jk, a nie na URL, ponieważ ta sama oferta pojawia się z różnymi parametrami śledzenia.
Paginacja i strony krajowe
Indeed paginuje za pomocą parametru start, który zwiększa się o 10. I to nie jest jedna strona — każdy kraj to subdomena: www.indeed.com dla USA, uk.indeed.com dla Wielkiej Brytanii i tak dalej. Dopasuj wyjście proxy do kraju, który zapytujesz, aby żądanie było geograficznie spójne:
def crawl(query, location, country="www", pages=5):
base = f"https://{country}.indeed.com/jobs"
for start in range(0, pages * 10, 10):
params = {"q": query, "l": location, "start": start}
html = requests.get(base, params=params, headers=headers,
proxies=proxies, timeout=30).text
# parse as above, yield rows
yield html
# freshness filter: fromage accepts only 1, 3, 7 or 14 days
# .../jobs?q=python&l=NYC&fromage=7
Jedna ciekawostka, którą warto znać: filtr "posted within" Indeed (fromage) akceptuje tylko 1, 3, 7 lub 14 dni — inne wartości są ignorowane, więc zbuduj swoją logikę świeżości wokół tych przedziałów.

Rzeczywistość Cloudflare
Indeed znajduje się za Cloudflare, więc adres IP z centrum danych z gołym żądaniem często otrzymuje wyzwanie zamiast wyników. Naprawy to zwykły stos anty-botowy: spójny User-Agent przeglądarki i zestaw nagłówków oraz — największa dźwignia — wyjście rezydencyjne, które nie jest wcześniej oceniane jako automatyzacja. Proxy rezydencyjne przedstawia się jako połączenie prawdziwego użytkownika, co utrzymuje Cloudflare w serwowaniu strony. Kiedy pojawia się wyzwanie, dopasowanie odcisku palca przeglądarki jest równie ważne jak IP; nasz przewodnik na temat przechodzenia przez Cloudflare w 2026 roku obejmuje, gdzie przebiega linia.
Skrót: pion SERP z ofertami pracy
Jeśli to, czego naprawdę chcesz, to dane rynku pracy — a nie konkretnie HTML Indeed — istnieje czystsza ścieżka. Pion z ofertami pracy Google agreguje ogłoszenia z Indeed i wielu innych tablic, a SERP API zwraca ten pion z ofertami pracy jako przetworzony JSON: tytuł, firma, lokalizacja, data publikacji i źródło, bez selektorów CSS do utrzymania i bez walki z Cloudflare. Wymieniasz pewną kontrolę na poziomie pól na stabilny strukturalny kanał z wielu tablic jednocześnie, co dla analizy zbiorczej zatrudnienia jest zazwyczaj lepszym rozwiązaniem. To ta sama logika, która stoi za budowaniem agregatora tablic ogłoszeń o pracę na kanale SERP zamiast jednego scraper'a na stronę.
Pobierz pion z ofertami pracy jako czysty JSON
Do czego dane są przydatne
Poza wyszukiwaniem pracy, te dane napędzają prawdziwą analizę: benchmarking wynagrodzeń według roli i miasta, śledzenie popytu na określone umiejętności w czasie, sygnały zatrudnienia konkurencji (rywalizacja zatrudniająca nowy zespół to strategia), i wzbogacenie — łączenie otwartych ról firmy z danymi firmograficznymi dla działań wychodzących. Połącz to z danymi o wynagrodzeniach z Glassdoor, a uzyskasz pełniejszy obraz wynagrodzeń niż z jednego źródła.

Często zadawane pytania
Czy można legalnie zeskrobywać ogłoszenia o pracę z Indeed?
Ogłoszenia o pracę to dane publiczne, a zbieranie publicznie widocznych list jest ogólnie obronne, ale warunki Indeed ograniczają automatyczny dostęp i należy unikać danych osobowych oraz respektować limity szybkości. Wiele zespołów omija kwestię warunków, korzystając z agregowanego pionu SERP z ofertami pracy zamiast bezpośredniego zeskrobywania Indeed. To ogólne informacje, a nie porada prawna — przejrzyj aktualne warunki przed dużym projektem.
Dlaczego mój scraper Indeed ciągle się psuje?
Dwa powody. Po pierwsze, Indeed rotuje swoje zhaszowane nazwy klas CSS, więc selektory przypięte do nich zawodzą w ciągu kilku tygodni — zakotwicz na atrybutach data-testid i kluczu pracy. Po drugie, Cloudflare zaczyna wyzywać twój IP, gdy zostanie oznaczony; wyjście rezydencyjne i spójny odcisk palca przeglądarki utrzymują ładowanie prawdziwej strony. Napraw oba i scraper się stabilizuje.
Jak zeskrobać oferty pracy z wielu krajów?
Indeed obsługuje każdy kraj z własnej subdomeny (www.indeed.com, uk.indeed.com, de.indeed.com i tak dalej). Zapytaj odpowiednią subdomenę i przejdź przez wyjście proxy w tym kraju, aby żądanie było geograficznie spójne — w przeciwnym razie możesz otrzymać niedopasowane lub przekierowane wyniki. Pion SERP z ofertami pracy również akceptuje parametr kraju, jeśli wolisz nie zarządzać subdomenami.
Czy Google jobs SERP jest lepszy niż zeskrobywanie Indeed?
Dla zbiorczej analizy rynku pracy zazwyczaj tak. Pion z ofertami pracy zwraca ogłoszenia z Indeed i wielu innych tablic jako strukturalny JSON, bez rotujących selektorów i bez wyzwań Cloudflare do obsługi. Tracisz niektóre pola specyficzne dla Indeed, ale zyskujesz stabilny kanał z wielu źródeł i znacznie mniej utrzymania. Zeskrobywanie bezpośrednio z Indeed tylko wtedy, gdy potrzebujesz pól, które są na własnych stronach Indeed.
Indeed nagradza trwałe podejście: zakotwicz na stabilnych atrybutach, deduplikuj według klucza pracy, paginuj po dziesiątkach i używaj rezydencyjnego IP, aby Cloudflare cię obsługiwało. A kiedy potrzebujesz tylko sygnału rynku pracy, a nie dokładnego HTML Indeed, pion SERP z ofertami pracy dostarcza go jako JSON. Wybierz ścieżkę, która odpowiada temu, ile kontroli nad polami faktycznie potrzebujesz.