Di satu titik — kira-kira saat saya sudah menyalin-tempel judul lowongan dari Indeed ke spreadsheet untuk ke-50 kalinya — saya mulai mempertanyakan pilihan karier saya. Kalau Anda pernah mencoba mengambil data terstruktur dari Indeed secara programatis, Anda pasti sudah tahu akhirnya: error 403 itu bukan bug, melainkan fitur dari sistem pertahanan Indeed.
Indeed adalah job board terbesar di dunia, dengan sekitar 350 juta pengunjung unik bulanan, 130 juta lowongan kerja pada waktu tertentu, dan operasi di 60+ negara. Itu menjadikannya salah satu sumber data pasar kerja paling kaya di planet ini — dan salah satu yang paling sulit di-scrape. Scraper open-source JobFunnel (ribuan bintang di GitHub) bahkan diarsipkan oleh maintainer-nya pada Desember 2025 setelah bertahun-tahun kalah dalam perlombaan melawan anti-bot. Kata-kata maintainer sendiri: "Semua pengguna bisa scrape beberapa lowongan, tetapi cepat kena captcha, lalu scraping gagal, dan tidak menghasilkan lowongan apa pun." Kontributor lain melaporkan CAPTCHA muncul pada request pertama. Jadi ya — ini bukan target scraping yang sederhana. Dalam panduan ini, saya akan membahas setiap metode praktis untuk scraping Indeed dengan Python, menunjukkan cara bertahan dari tantangan 403, dan — untuk Anda yang ingin melewati debugging sama sekali — mendemonstrasikan alternatif no-code menggunakan Thunderbit.
Apa Arti Scrape Indeed dengan Python?
Pada dasarnya, web scraping adalah pengambilan data terstruktur dari halaman web secara otomatis. Saat kita bicara soal scraping Indeed dengan Python, maksudnya adalah menulis skrip yang membuka halaman hasil pencarian dan halaman detail lowongan Indeed, membaca HTML dasar (atau data yang disematkan), lalu mengekstrak field seperti judul pekerjaan, perusahaan, lokasi, gaji, dan deskripsi ke format yang bisa dipakai — CSV, database, atau Google Sheet.
Pustaka Python yang umum dipakai biasanya Requests (untuk HTTP call), BeautifulSoup (untuk parsing HTML), serta Selenium atau Playwright (untuk otomasi browser). Tapi Indeed bukan situs statis biasa. Ini situs hibrida: HTML yang dirender server dengan blob state JSON yang disematkan, di depan Cloudflare Bot Management. Artinya, scraper Anda harus menangani konten yang dirender JavaScript, nama class CSS yang berubah-ubah, dan proteksi anti-bot yang agresif — semua itu sebelum Anda sempat mem-parse satu judul lowongan pun.
Selain itu, di 2026 juga tidak ada API Indeed resmi, gratis, dan read-only. Publisher Jobs API yang lama sudah dihentikan sekitar 2020, dan yang tersisa hanya untuk sisi employer (Job Sync, Sponsored Jobs). Jadi, scraping atau membayar penyedia data pihak ketiga adalah dua opsi yang paling realistis.
Mengapa Perlu Scrape Data Lowongan Indeed?
Alasan bisnis untuk scraping Indeed cukup jelas: menelusuri ribuan listing secara manual tidak praktis, dan data di dalam listing itu memang sangat bernilai.

| Kasus Penggunaan | Siapa yang Diuntungkan | Contoh |
|---|---|---|
| Generasi prospek | Tim sales & rekrutmen | Membangun daftar perusahaan yang sedang merekrut beserta info kontak |
| Riset pasar kerja | Analis, tim HR | Mengidentifikasi skill yang sedang tren, benchmark gaji per wilayah |
| Intelijen kompetitif | Employer, agensi staffing | Memantau pola perekrutan dan tawaran gaji kompetitor |
| Otomasi pencarian kerja pribadi | Pencari kerja | Menggabungkan listing yang cocok dengan kriteria Anda di berbagai lokasi |
| Data pelatihan untuk model ML | Data scientist | Membangun model prediksi gaji dari data historis |
Riset dari Indeed Hiring Lab sendiri memvalidasi bahwa data lowongan sangat selaras dengan BLS JOLTS dan bisa jadi proksi hampir real-time untuk kondisi pasar tenaga kerja AS. Hedge fund menggunakan kecepatan posting lowongan sebagai sinyal data alternatif. Tim HR membandingkan kompensasi memakai rentang gaji hasil scraping. Dan recruiter menyusun daftar prospek dari perusahaan yang sedang aktif merekrut.
Satu catatan praktis: data gaji di Indeed memang makin bagus, tetapi masih belum lengkap. Per pertengahan 2025, sekitar 59% posting di AS menyertakan info gaji, tetapi hanya sekitar 22% yang memberi angka pasti — sisanya berupa rentang. Analisis gaji apa pun yang dibangun dari data Indeed perlu memperhitungkan kekosongan ini.
Memilih Metode untuk Scrape Indeed dengan Python
Tidak ada satu cara yang paling benar untuk scrape Indeed. Pendekatan terbaik bergantung pada tingkat keahlian Anda, jumlah data yang dibutuhkan, dan seberapa besar maintenance yang siap Anda tanggung. Saya sudah menguji empat pendekatan utama, dan berikut perbandingannya:
| Kriteria | BS4 + Requests | Selenium | Hidden JSON (window.mosaic) | No-Code (Thunderbit) |
|---|---|---|---|---|
| Tingkat kesulitan | Pemula | Menengah | Menengah-Lanjut | Tidak ada (2 klik) |
| Kecepatan | Cepat | Lambat (render browser) | Cepat | Cepat (cloud scraping) |
| Konten yang dirender JS | Tidak | Ya | Ya (data disematkan) | Ya |
| Ketahanan terhadap anti-bot | Rendah | Sedang (dapat dideteksi) | Sedang-Tinggi | Tinggi (ditangani otomatis) |
| Maintenance saat HTML berubah | Tinggi (selector bisa rusak) | Tinggi | Sedang (struktur JSON lebih stabil) | Tidak ada (AI beradaptasi) |
| Paling cocok untuk | Prototipe cepat | Halaman dinamis, login-gated | Data terstruktur skala besar | Non-developer, hasil cepat |
Panduan ini membahas tiap metode. Kalau Anda developer Python, bagian BS4, Hidden JSON, dan Selenium layak dibaca. Kalau Anda bukan coder (atau sudah lelah debugging 403), lompat saja ke bagian Thunderbit.
Sebelum Memulai
- Tingkat kesulitan: Pemula hingga Menengah (bagian Python); Tidak ada (bagian Thunderbit)
- Waktu yang dibutuhkan: ~20–60 menit untuk setup Python dan scrape pertama; ~2 menit dengan Thunderbit
- Yang Anda perlukan: Python 3.9+, editor kode, browser Chrome, dan (untuk jalur no-code) Thunderbit Chrome Extension
Menyiapkan Lingkungan Python untuk Scraping Indeed
Sebelum menulis kode scraping apa pun, siapkan dulu environment Anda.
Instal Library yang Dibutuhkan
Buat virtual environment dan instal paket yang diperlukan:
python -m venv indeed_env
source indeed_env/bin/activate # Di Windows: indeed_env\Scripts\activate
# Untuk pendekatan HTTP + parsing
pip install requests beautifulsoup4 lxml httpx
# Untuk pendekatan hidden JSON (direkomendasikan)
pip install curl_cffi parsel tenacity
# Untuk pendekatan otomasi browser
pip install selenium
Beberapa catatan:
curl_cffiadalah default 2026 untuk scraping situs yang dilindungi Cloudflare. Library ini meniru fingerprint TLS browser asli, sesuatu yang tidak bisa dilakukanrequestsdanhttpxbiasa. Nanti kita bahas kenapa ini penting di bagian anti-bot.- Selenium 4.6+ sudah menyertakan Selenium Manager, jadi Anda tidak perlu lagi mengunduh ChromeDriver secara manual — binary browser dikelola otomatis.
- Gunakan
lxmlsebagai backend parser untuk BeautifulSoup. Kecepatannya sekitar 1,5x lebih cepat daripadahtml.parserbawaan stdlib.
Buat Struktur Proyek Anda
Buat sederhana:
indeed_scraper/
├── scraper.py
├── requirements.txt
└── output/
Semua contoh kode di bawah ini dibangun di atas scraper.py.
Cara Scrape Indeed dengan Python Menggunakan BeautifulSoup
Ini pendekatan yang ramah pemula: gunakan requests untuk mengambil halaman dan BeautifulSoup untuk mem-parsing HTML. Setup-nya paling cepat, tapi juga paling rapuh di Indeed.
Langkah 1: Bangun URL Pencarian Indeed
URL pencarian Indeed mengikuti pola yang mudah diprediksi:
https://www.indeed.com/jobs?q=<query>&l=<location>&start=<offset>
Misalnya, mencari "data analyst" di "Austin, TX" mulai dari halaman pertama:
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 melakukan pagination per kelipatan 10, dengan batas keras 1.000 hasil (start <= 990). Offset di atas 990 akan diam-diam mengembalikan halaman yang sama.
Langkah 2: Kirim HTTP Request dengan Header yang Tepat
Indeed langsung memblokir request dengan user-agent Python default. Anda butuh header yang realistis:
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)
Kalau Anda mendapat 200, untuk saat ini Anda aman. Kalau mendapat 403, berarti Cloudflare berhasil menangkap Anda. (Cara bertahannya akan kita bahas nanti.)
Langkah 3: Parse Listing Lowongan dari HTML
Gunakan BeautifulSoup untuk memilih elemen kartu lowongan. Targetkan atribut data-testid — atribut ini lebih stabil daripada nama class CSS acak milik Indeed:
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"Ditemukan {len(jobs)} lowongan")
Langkah 4: Tangani Pagination
Lakukan loop antar halaman dengan menaikkan parameter start:
import time, random
all_jobs = []
for page in range(0, 50, 10): # 5 halaman pertama
params["start"] = page
url = f"https://www.indeed.com/jobs?{urlencode(params)}"
response = requests.get(url, headers=headers, timeout=30)
# ... parse seperti di atas ...
all_jobs.extend(jobs)
time.sleep(random.uniform(3, 6))
Keterbatasan Pendekatan Ini
Saya akan jujur: BS4 + Requests adalah metode terlemah untuk Indeed di 2026. requests biasa memakai library TLS stdlib Python, yang menghasilkan fingerprint JA3 yang langsung dikenali Cloudflare sebagai "bukan browser." Library ini juga tidak mendukung HTTP/2, padahal Indeed menyajikannya. Anda kemungkinan besar akan diblokir setelah beberapa halaman. Lalu soal CSS selector? Indeed sering mengubah class name seperti css-1m4cuuf dan jobsearch-JobComponent-embeddedBody-1n0gh5s secara berkala — jadi selector yang menargetkannya ibarat bom waktu.
Gunakan metode ini untuk prototyping cepat pada satu halaman. Untuk skala apa pun, gunakan pendekatan hidden JSON.
Cara Scrape Indeed dengan Python Menggunakan Hidden JSON Data
Ini metode yang saya rekomendasikan untuk sebagian besar developer Python. Alih-alih mem-parse elemen HTML yang rapuh, Anda mengekstrak data terstruktur dari variabel JavaScript yang tertanam di source halaman Indeed: window.mosaic.providerData["mosaic-provider-jobcards"].
Semua field yang Anda butuhkan — judul pekerjaan, perusahaan, lokasi, gaji, job key, tanggal posting, flag remote — sudah ada di blob JSON ini. Tidak perlu eksekusi JavaScript. Skemanya stabil setidaknya sejak 2023, sehingga jauh lebih tangguh daripada selector DOM.
Langkah 1: Ambil HTML Halaman
Gunakan curl_cffi вместо requests — library ini meniru fingerprint TLS browser asli, yang sangat penting untuk bertahan dari 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))
Mengapa curl_cffi? Ini adalah binding Python di atas curl-impersonate, yang mereproduksi tepat TLS ClientHello, frame HTTP/2 SETTINGS, dan urutan header milik browser asli. Ini satu-satunya HTTP client Python yang masih aktif dipelihara dan mampu menaklukkan JA3/JA4 sekaligus fingerprint Akamai H2 dalam satu panggilan. Target impersonasi yang didukung mencakup varian chrome120, chrome124, chrome131, Safari, dan Edge.
Langkah 2: Ekstrak JSON dengan Regular Expression
Blob JSON tertanam di tag <script>. Ambil dengan 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"Ditemukan {len(results)} lowongan di hidden JSON")
else:
print("Hidden JSON tidak ditemukan — kemungkinan diblokir atau halaman berubah")
Langkah 3: Parse Field Lowongan dari JSON
Setiap item di results berisi lebih banyak data daripada yang terlihat di halaman:
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 ini sering menyertakan estimasi gaji, atribut taksonomi (tag skill), dan rating perusahaan yang tidak selalu terlihat di HTML hasil render.
Langkah 4: Scrape Banyak Halaman
Gunakan tierSummaries di JSON untuk memahami total hasil, lalu lakukan loop:
import time, random
all_jobs = []
for start in range(0, 50, 10): # 5 halaman pertama
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"Total: {len(all_jobs)} lowongan berhasil di-scrape")
Mengapa Hidden JSON Lebih Tangguh
Struktur window.mosaic.providerData berubah lebih jarang daripada nama class CSS. Anda mendapat data yang bersih dan terstruktur tanpa perlu mem-parsing HTML yang berantakan. Meski begitu, Anda tetap perlu mitigasi anti-bot (header, jeda, proxy) — dan itu akan kita bahas berikutnya.
Cara Scrape Indeed dengan Python Menggunakan Selenium
Selenium adalah pendekatan otomasi browser. Ini berguna saat Anda perlu berinteraksi dengan halaman — mengklik panel detail lowongan, menangani konten yang gated login, atau scraping deskripsi yang dimuat dinamis dan tidak ada di HTML awal.
Kapan Harus Menggunakan Selenium Alih-alih HTTP Client
- Indeed memuat sebagian konten secara dinamis (deskripsi penuh di panel kanan)
- Anda perlu scraping halaman yang memerlukan state sesi atau login
- Anda melakukan scraping skala kecil di mana kecepatan bukan prioritas utama
Panduan Singkat
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 lebih mudah terdeteksi — gunakan hati-hati
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()
Keterbatasan
Selenium lambat — setiap halaman perlu dirender browser sepenuhnya. Chrome headless dapat dideteksi oleh sistem anti-bot Indeed (Cloudflare memeriksa navigator.webdriver, string vendor WebGL, jumlah plugin, dan lainnya). Bahkan undetected-chromedriver hanya menunda deteksi; ia tidak mencegahnya secara permanen. Dan seperti BS4, selector Anda akan rusak saat Indeed memperbarui UI-nya.
Untuk sebagian besar kasus, pendekatan hidden JSON memberi data yang sama, lebih cepat, dan dengan maintenance yang lebih ringan. Simpan Selenium untuk edge case saat Anda benar-benar membutuhkan browser.
Cara Menghindari Error 403 Saat Scraping Indeed dengan Python
Ini bagian yang paling penting. Kalau Anda sampai di sini setelah frustrasi mencari di Google, berarti Anda ada di tempat yang tepat.

Mengapa Indeed Memblokir Scraper Anda
Indeed menggunakan Cloudflare Bot Management plus Cloudflare Turnstile — bukan DataDome, bukan PerimeterX. Header respons mengonfirmasi hal itu: server: cloudflare, cf-ray, dan cookie bot-management __cf_bm. Cloudflare memeriksa fingerprint TLS Anda (JA3/JA4), urutan header HTTP/2, pola request, dan sinyal perilaku browser. Kalau salah satu terlihat tidak manusiawi, Anda akan mendapat 403, 429, 503, atau — yang paling licik — 200 OK dengan halaman tantangan Turnstile alih-alih data lowongan yang sebenarnya.
Rotasi User-Agent dan Header Request
Satu User-Agent statis adalah cara tercepat untuk diblokir. Lakukan rotasi dari kumpulan string yang realistis dan terbaru. Penting: field minor version Chrome dibekukan di 0.0.0 sejak User-Agent Reduction — jangan mengarang minor version non-nol, karena anti-bot akan langsung menandainya.
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",
}
Pastikan juga Client Hints sec-ch-ua Anda cocok dengan versi UA. sec-ch-ua: "Chrome";v="131" yang dipasangkan dengan User-Agent yang mengklaim Chrome 145 adalah red flag instan.
Tambahkan Jeda Acak Antar Request
Interval yang tetap mudah dikenali polanya. Gunakan jitter acak:
import time, random
# Di antara setiap request
time.sleep(random.uniform(3, 6))
# Saat retry setelah diblokir
def backoff_sleep(attempt):
base = 4
sleep_time = base * (2 ** attempt) + random.uniform(0, 2)
time.sleep(min(sleep_time, 60))
Konsensus lapangan dari ScrapeOps dan WebScraping.AI adalah 3–6 detik antar request per IP, dengan batas keras sekitar 100 request per IP per sesi sebelum rotasi.
Gunakan Rotasi Proxy
Ini adalah faktor penentu keberhasilan yang paling besar. Proxy datacenter dari rentang AWS/GCP biasanya hanya mencapai sekitar 5–15% keberhasilan pada target Cloudflare Enterprise — praktis tidak berguna untuk Indeed. Proxy residential plus fingerprint TLS yang benar bisa naik ke 80–95% keberhasilan.
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,
)
Harga proxy residential pada 2026 berkisar sekitar $4–8,50 per GB tergantung penyedia dan level komitmen. Untuk Indeed, mulailah dengan pool kecil lalu scale up bila perlu.
Tangani Kode Status 403, 429, dan 503 dengan Baik
Jangan sekadar retry membabi buta. Kode status yang berbeda berarti hal yang berbeda:
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,
)
# Cek kasus licik "200 tapi berisi 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 — diblokir. Mengganti proxy, percobaan {attempt + 1}")
elif r.status_code == 429:
print("429 — rate limited. Perlambat permintaan.")
elif r.status_code == 503:
print("503 — server overload atau JS challenge.")
backoff_sleep(attempt)
except Exception as e:
print(f"Error request: {e}")
backoff_sleep(attempt)
raise RuntimeError(f"Gagal setelah {max_retries} kali percobaan: {url}")
Kasus 200-dengan-challenge adalah yang paling tricky. Selalu pindai body respons untuk marker cf-turnstile atau Just a moment sebelum menganggap 200 sebagai sukses.
Alternatif yang Lebih Mudah: Biarkan Thunderbit Menangani Anti-Bot
Untuk pengguna yang tidak ingin membangun dan memelihara pool proxy, rotasi header, dan impersonasi fingerprint TLS, cloud scraping dari Thunderbit menangani CAPTCHA, rotasi proxy, dan proteksi anti-bot secara otomatis. Tidak perlu setup proxy, tidak perlu konfigurasi curl_cffi, tidak perlu library pemecah CAPTCHA. Ini jalur paling minim hambatan kalau Anda hanya butuh datanya.
Mengapa Scraper Indeed Anda Terus Rusak (Dan Cara Memperbaikinya)
Tembok 403 adalah rasa sakit akut. Rasa sakit kronisnya adalah maintenance — scraper yang bekerja hari ini bisa rusak minggu depan, diam-diam mengembalikan data kosong atau hasil lama.
Cara Indeed Merusak Selector Anda
Indeed sering merotasi nama class CSS. Panduan Bright Data secara eksplisit memperingatkan bahwa class seperti css-1m4cuuf dan css-1rqpxry "tampaknya dihasilkan secara acak — kemungkinan saat build." A/B testing berarti sesi yang berbeda bisa melihat layout halaman yang berbeda. Dan restrukturisasi DOM bisa terjadi tanpa pemberitahuan.
Kisah JobFunnel sangat informatif. Seorang kontributor melaporkan: "CaptchaBuster berhasil mengatasi captcha, dan alasan scraping halaman [masih] gagal adalah karena selector BeautifulSoup sudah usang." Scraper-nya bukan diblokir — ia justru mem-parsing elemen yang salah.
Strategi: Utamakan Hidden JSON daripada Parsing DOM
Blob window.mosaic.providerData sudah stabil secara skema setidaknya sejak 2023. Path metaData.mosaicProviderJobCardsModel.results[] masih canonical di 2026. DOM selector rusak tiap bulan. Ekstraksi JSON mungkin rusak setahun sekali, atau bahkan tidak sama sekali.
Strategi: Gunakan Data Attribute, Bukan Class Name
Saat Anda memang harus menyentuh DOM, targetkan atribut fungsional:
| Selector | Tujuan |
|---|---|
[data-testid="slider_item"] | Kontainer tiap kartu lowongan |
[data-testid="job-title"] atau h2.jobTitle > a | Link judul lowongan |
[data-testid="company-name"] | Nama perusahaan |
[data-testid="text-location"] | Teks lokasi |
data-jk="<jobkey>" pada tiap kartu | Hook paling stabil — tidak berubah sejak 2019 |
Tambahkan Assertion Check untuk Mendeteksi Selector yang Usang
Jangan pernah membiarkan scraper berjalan diam-diam dengan hasil nol. Tambahkan pengecekan setelah setiap fetch:
results = parse_hidden_json(html)
assert len(results) > 0, (
f"Indeed mengembalikan hasil kosong pada start={start} — "
"kemungkinan diblokir, CAPTCHA, atau selector bergeser. "
f"500 karakter pertama respons: {html[:500]}"
)
Catat 500–2000 karakter pertama dari respons mentah saat gagal. Dengan begitu, Anda bisa langsung tahu apakah yang Anda dapat adalah tantangan Turnstile, dinding login, atau perubahan skema. Jalankan smoke test harian di level CI terhadap query tetap (misalnya, q=python&l=remote) yang memastikan hasilnya tidak nol.
Alternatif AI: Scraper yang Tidak Pernah Mudah Rusak
AI Thunderbit membaca struktur halaman baru setiap kali — tidak bergantung pada selector hardcoded atau pola regex. Saat HTML Indeed berubah, Thunderbit beradaptasi otomatis. Ini langsung menjawab beban maintenance yang secara konsisten disebut pengguna forum sebagai sumber frustrasi utama. Kalau Anda pernah bangun lalu melihat pesan Slack berisi "scraper-nya kosong lagi," Anda tahu betapa berharganya tidak perlu memperbaikinya.
Scrape Indeed Tanpa Menulis Python: Alternatif No-Code
Setiap panduan pesaing biasanya mengasumsikan Anda akan menulis kode Python. Tapi data forum bercerita lain. Pengguna mengatakan hal seperti "ini memang sangat sulit dengan bug dan error yang terus muncul" dan ada yang menyarankan menyewa orang di Fiverr hanya untuk mendapatkan datanya. Kalau itu terdengar seperti Anda, bagian ini adalah jalan keluar Anda.
Cara Scrape Indeed dengan Thunderbit (Langkah demi Langkah)
Langkah 1: Instal Thunderbit Chrome Extension dari Chrome Web Store. Gratis untuk memulai.
Langkah 2: Buka halaman hasil pencarian Indeed di browser Anda — misalnya, https://www.indeed.com/jobs?q=data+analyst&l=Austin%2C+TX.
Langkah 3: Klik ikon Thunderbit di toolbar browser, lalu klik "AI Suggest Fields." AI Thunderbit memindai halaman dan otomatis mendeteksi kolom seperti Job Title, Company, Location, Salary, Job URL, dan Posted Date. Anda bisa meninjau dan menyesuaikan field yang disarankan — hapus kolom yang tidak Anda perlukan, atau tambahkan kolom kustom dengan mendeskripsikan kebutuhan Anda dalam bahasa Inggris biasa.
Langkah 4: Klik "Scrape." Thunderbit mengekstrak data dari halaman dan menampilkannya dalam tabel terstruktur. Anda akan melihat baris-baris lowongan dengan field yang sudah Anda konfigurasi.
Perkaya dengan Scraping Subpage
Setelah halaman listing di-scrape, klik "Scrape Subpages" agar Thunderbit mengunjungi setiap halaman detail lowongan satu per satu. Ia mengambil deskripsi lengkap, kualifikasi, benefit, dan tautan lamaran — tanpa setup tambahan. Ini setara dengan menulis scraper Python kedua untuk mengunjungi setiap URL /viewjob?jk=<jobkey>, hanya saja cukup satu klik.
Tangani Pagination Secara Otomatis
Thunderbit menangani pagination berbasis klik di Indeed secara otomatis. Tidak perlu menyusun URL offset secara manual atau menulis loop pagination. Ia mengklik antar halaman dan menggabungkan hasilnya.
Ekspor ke Tool Favorit Anda
Ekspor data hasil scraping ke CSV, Excel, Google Sheets, Airtable, atau Notion — sepenuhnya gratis. Tidak perlu menulis kode csv.writer() atau pandas.to_csv().
Kapan Menggunakan Python vs. Thunderbit
| Skenario | Tool Terbaik |
|---|---|
| Pipeline data kustom, otomasi terjadwal lewat cron/Airflow | Python |
| Integrasi ke codebase yang lebih besar | Python |
| Logika parsing yang sangat disesuaikan | Python |
| Riset sekali jalan atau analisis pasar | Thunderbit |
| Anggota tim non-teknis butuh data | Thunderbit |
| Mendapatkan data sekarang tanpa debugging 403 | Thunderbit |
| Perkayaan subpage tanpa setup apa pun | Thunderbit |
Perbandingan waktu: setup Python + debugging anti-bot = jam sampai hari (terutama untuk pertama kalinya). Thunderbit = di bawah 2 menit untuk data yang sama. Bukan berarti Python salah — maksudnya, semuanya tergantung kebutuhan Anda.
Apakah Scraping Indeed Legal? Yang Perlu Anda Tahu
Tidak satu pun panduan scraping Indeed yang masuk peringkat teratas membahas legalitas, padahal pertanyaan "Apakah scraping Indeed legal?" sering muncul di forum. Ini bukan nasihat hukum, tapi berikut gambaran umumnya.
Ketentuan Layanan Indeed
ToS Indeed (indeed.com/legal) tidak memuat klausul umum "dilarang scraping." Satu-satunya larangan otomatisasi yang eksplisit ada di Bagian A.3.5, yang melarang "penggunaan automasi, scripting, atau bot untuk mengotomatisasi proses Indeed Apply." Itu cakupannya sempit, hanya pada alur Apply, bukan membaca secara pasif listing lowongan publik. Alat penegakan utama Indeed bersifat teknis — tantangan Cloudflare, pemblokiran IP, fingerprint perangkat — bukan ruang sidang.
Preseden Hukum yang Relevan
Kasus AS yang paling sering dikutip adalah hiQ Labs v. LinkedIn. Pengadilan Sirkuit ke-9 memutuskan pada April 2022 bahwa scraping data yang bisa diakses publik "kemungkinan tidak melanggar CFAA" (Computer Fraud and Abuse Act). Namun, kemudian hiQ dinyatakan bertanggung jawab atas breach of contract karena karyawannya membuat profil LinkedIn palsu dan menerima ToS.
Baru-baru ini, Meta v. Bright Data (N.D. Cal., Januari 2024) menghasilkan putusan yang bahkan lebih jelas. Hakim Chen memutuskan bahwa Ketentuan Facebook dan Instagram "tidak melarang scraping data publik saat logout." Meta kemudian secara sukarela mencabut sisa klaimnya bulan berikutnya.
robots.txt Indeed
robots.txt Indeed secara umum melarang /jobs/ dan /job/ untuk User-agent: * default, tetapi secara eksplisit mengizinkan Googlebot dan Bingbot mengakses /viewjob? — halaman detail lowongan individual. Crawler pelatihan AI (GPTBot, CCBot, anthropic-ai) dibatasi secara ketat. robots.txt tidak mengikat secara hukum di AS, tetapi mematuhinya adalah praktik terbaik dan bukti itikad baik.
Pedoman Praktis untuk Scraping yang Bertanggung Jawab
- Hanya scrape data yang tersedia publik — jangan login, jangan buat akun palsu
- Hormati batas rate limit: 1 request setiap 3–6 detik per IP, concurrency satu digit
- Jangan terbitkan ulang data hasil scraping sebagai job board milik Anda sendiri
- Gunakan data untuk riset pribadi atau internal, bukan jual-beli komersial tanpa izin
- Hapus atau hash PII yang tidak Anda perlukan; tetapkan batas retensi untuk data yang berdekatan dengan data pribadi
- Jika Anda beroperasi dalam skala besar atau di Uni Eropa/Inggris, konsultasikan dengan pengacara — kewajiban transparansi Pasal 14 GDPR berlaku untuk data pribadi hasil scraping
Spektrum risikonya: otomasi pencarian kerja pribadi ada di ujung rendah. Penjualan ulang data Indeed secara komersial dalam skala besar ada di ujung tinggi.
Kesimpulan dan Poin Utama
Scraping Indeed dengan Python itu bisa dilakukan, tetapi bukan proyek akhir pekan yang tinggal jalan lalu dilupakan. Proteksi Cloudflare Indeed, selector yang terus berganti, dan langkah anti-bot yang agresif berarti Anda perlu mendekatinya dengan tool yang tepat dan ekspektasi yang tepat.
Ini yang paling saya petik dari semuanya:
- Indeed adalah sumber data pasar kerja terkaya di web — 350 juta pengunjung bulanan, 130 juta listing — tetapi perlawanan terhadap scraper sangat kuat.
- Ekstraksi hidden JSON (
window.mosaic.providerData) adalah pendekatan Python paling tangguh. Skemanya stabil selama bertahun-tahun, sementara selector CSS rusak tiap bulan. curl_cffidengan browser impersonation adalah HTTP client default 2026 untuk situs yang dilindungi Cloudflare.requestsdanhttpxbiasa bisa diblokir hanya karena fingerprint TLS.- Selalu gunakan header rotasi, jeda acak, dan proxy residential untuk menghindari error 403. Proxy datacenter hampir tidak berguna melawan Cloudflare Enterprise.
- Tambahkan assertion check agar Anda langsung tahu saat selector rusak atau saat yang Anda terima adalah halaman challenge, bukan data lowongan.
- Bagi pengguna non-teknis atau siapa pun yang ingin hasil cepat, Thunderbit menyediakan jalur no-code berbasis AI yang beradaptasi otomatis terhadap perubahan situs — tanpa proxy, tanpa debugging, tanpa maintenance.
Kalau Anda ingin mencoba jalur no-code, Thunderbit menawarkan tier gratis sehingga Anda bisa mengujinya di Indeed tanpa komitmen apa pun. Dan kalau Anda memilih jalur Python, contoh kode di atas adalah titik awal yang solid — hanya saja, ingatlah bahwa ketahanan anti-bot harus dianggap sebagai prioritas utama, bukan pemikiran belakangan.
Untuk pembahasan lebih lanjut tentang pendekatan dan tool web scraping, lihat panduan kami tentang cara web scrape dengan Python, tool web scraping otomatis terbaik, dan web scraping tanpa kena blokir. Anda juga bisa menonton tutorial di Thunderbit YouTube Channel.
Coba Thunderbit untuk Scrape Data Indeed Lebih Cepat Get Started Free
FAQ
Library Python apa yang paling bagus untuk scraping Indeed?
Untuk HTTP request, curl_cffi adalah pilihan terkuat di 2026 — ia meniru fingerprint TLS browser asli, yang penting untuk melewati Cloudflare. httpx dengan HTTP/2 adalah fallback yang lumayan untuk target yang tidak terlalu dilindungi. Untuk parsing HTML, BeautifulSoup4 dengan lxml tetap jadi standar. Untuk otomasi browser, Playwright (dengan playwright-stealth) atau undetected-chromedriver bisa dipakai, meski keduanya makin mudah dideteksi. Pendekatan regex hidden JSON (window.mosaic.providerData) menghindari parsing berat sama sekali.
Kenapa saya terus mendapat error 403 saat scraping Indeed?
Indeed memakai Cloudflare Bot Management, yang memeriksa fingerprint TLS Anda (JA3/JA4), urutan header HTTP/2, pola request, dan perilaku browser. Kalau Anda memakai requests biasa, fingerprint TLS Anda langsung mengidentifikasi Anda sebagai skrip Python — 403 muncul bahkan sebelum header dibaca. Perbaiki dengan pindah ke curl_cffi dengan browser impersonation, merotasi string User-Agent yang realistis, menambahkan jeda acak (3–6 detik), dan memakai proxy residential. Juga periksa kasus "200 dengan Turnstile challenge" — pindai body respons untuk marker cf-turnstile.
Bisa kah saya scrape Indeed tanpa coding?
Bisa. Tool seperti Thunderbit memungkinkan Anda mengekstrak listing lowongan Indeed hanya dalam beberapa klik — instal extension Chrome, buka halaman pencarian Indeed, klik "AI Suggest Fields," lalu "Scrape." AI Thunderbit otomatis mendeteksi field seperti judul pekerjaan, perusahaan, lokasi, dan gaji. Ia menangani pagination, enrichment subpage (deskripsi lowongan lengkap), dan proteksi anti-bot secara otomatis. Ekspor ke CSV, Google Sheets, Airtable, atau Notion gratis.
Seberapa sering Indeed mengubah struktur HTML-nya?
Indeed secara rutin merotasi nama class CSS (misalnya, css-1m4cuuf, string hash acak) dan merestrukturisasi elemen DOM tanpa pemberitahuan. A/B testing berarti pengguna yang berbeda bisa melihat layout yang berbeda secara bersamaan. Pendekatan hidden JSON (window.mosaic.providerData) jauh lebih stabil — skemanya konsisten setidaknya sejak 2023. Saat Anda harus memakai selector DOM, targetkan atribut data-testid dan data-jk (job key), bukan class CSS.
Apakah legal untuk scraping Indeed?
Scraping saat logout pada URL lowongan Indeed yang dapat diakses publik kemungkinan kecil menimbulkan tanggung jawab CFAA di AS, berdasarkan putusan Sirkuit ke-9 dalam hiQ v. LinkedIn (2022) dan keputusan Meta v. Bright Data (2024). ToS Indeed melarang otomatisasi proses Apply secara spesifik, bukan membaca listing publik secara pasif. Meski begitu, selalu scrape secara bertanggung jawab: jangan login, jangan buat akun palsu, hormati rate limit, jangan menerbitkan ulang data sebagai job board milik sendiri, dan tangani data pribadi apa pun (nama recruiter, email) dengan hati-hati di bawah GDPR/CCPA. Untuk operasi skala komersial, konsultasikan dengan pengacara.
Pelajari Lebih Lanjut
- Cara Melakukan Web Scraping Tanpa Kena Blokir di Python
- Python Web Scraping: Hindari Blokir dengan Penggunaan Proxy yang Cerdas
- Cara Menulis Web Scraper dengan Python: Dari Awal sampai Selesai
- Cara Mengambil Data dari Website Menggunakan Python Secara Efisien
- Cara Scrape Data Menggunakan Python: Tutorial untuk Pemula


