في مرة ما، قرب أني أنسخ المسمى الوظيفي رقم خمسين من Indeed إلى جدول بيانات، بدأت أشك فعلًا في اختياراتي المهنية. وإذا سبق لك أن حاولت سحب بيانات منظمة من Indeed برمجيًا، فأنت تعرف القصة: خطأ 403 ليس خللًا — بل هو جزء من منظومة الحماية في Indeed.
Indeed هو أكبر موقع وظائف في العالم، مع ما يقرب من 350 مليون زائر فريد شهريًا، و130 مليون إعلان وظيفي في أي لحظة، وعمليات في أكثر من 60 دولة. وهذا يجعله واحدًا من أغنى مصادر بيانات سوق العمل على الكوكب — وأحد أصعبها للاستخراج. أداة الاستخراج مفتوحة المصدر JobFunnel (التي حصدت آلاف النجوم على GitHub) تم أرشفتها حرفيًا بواسطة مطوّرها في ديسمبر 2025 بعد سنوات من مطاردة أنظمة مكافحة الروبوتات. ووفقًا لكلام المطوّر نفسه: "يمكن لجميع المستخدمين استخراج بعض الوظائف، لكنهم يصطدمون سريعًا بالكابتشا، ويفشل الاستخراج، فلا يتم الحصول على أي وظائف." كما أفاد مساهم آخر بالحصول على CAPTCHA في أول طلب مباشرة. لذا نعم — هذا ليس هدفًا سهلًا للاستخراج. في هذا الدليل، سأشرح كل طريقة عملية لاستخراج بيانات Indeed باستخدام Python، وأوضح لك كيف تتخطى عقبة 403 فعلًا، ولمن يفضّل تجنب متاعب التصحيح بالكامل — سأعرض أيضًا بديلًا بدون كود باستخدام Thunderbit.
ماذا يعني استخراج بيانات Indeed باستخدام Python؟
استخراج الويب، ببساطة، هو السحب الآلي للبيانات المنظمة من صفحات الويب. وعندما نتحدث عن استخراج Indeed باستخدام Python، فنحن نعني كتابة سكربت يزور صفحات نتائج البحث وصفحات تفاصيل الوظائف في Indeed، ويقرأ HTML الأساسي (أو البيانات المضمّنة)، ثم يستخرج حقولًا مثل المسمى الوظيفي، الشركة، الموقع، الراتب، والوصف إلى صيغة يمكن استخدامها — مثل CSV أو قاعدة بيانات أو Google Sheet.
المكتبات الشائعة في Python لهذا الغرض هي Requests لطلبات HTTP، وBeautifulSoup لتحليل HTML، وSelenium أو Playwright لأتمتة المتصفح. لكن Indeed ليس موقعًا ثابتًا بسيطًا. إنه موقع هجين: HTML يُولَّد على الخادم مع كتلة JSON مضمّنة، وتديره Cloudflare Bot Management في الواجهة. وهذا يعني أن أداة الاستخراج لديك تحتاج إلى التعامل مع المحتوى المولّد بواسطة JavaScript، وأسماء CSS المتغيرة، وحمايات مكافحة الروبوتات العدوانية — وكل ذلك قبل أن تحلل أول مسمى وظيفي.
ولا توجد أيضًا واجهة Indeed API رسمية ومجانية للقراءة فقط في 2026. واجهة Publisher Jobs API القديمة أُهمِلت تقريبًا حول عام 2020، وما بقي مخصص لأصحاب العمل فقط (Job Sync، Sponsored Jobs). لذا فإن الاستخراج أو الدفع إلى مزوّد بيانات خارجي هما الخياران الواقعيان الوحيدان.
لماذا تستخراج بيانات وظائف Indeed؟
الحجة التجارية لاستخراج بيانات Indeed واضحة: التصفح اليدوي لآلاف الإعلانات غير عملي، والبيانات داخل هذه الإعلانات ذات قيمة فعلية.

| حالة الاستخدام | من يستفيد | مثال |
|---|---|---|
| توليد العملاء المحتملين | فرق المبيعات والتوظيف | بناء قوائم بالشركات التي توظف مع معلومات التواصل |
| أبحاث سوق العمل | المحللون وفرق الموارد البشرية | تحديد المهارات الرائجة ومعايير الرواتب حسب المنطقة |
| استخبارات تنافسية | أصحاب العمل وشركات التوظيف | مراقبة أنماط التوظيف لدى المنافسين وعروض الرواتب |
| أتمتة البحث الشخصي عن وظائف | الباحثون عن عمل | تجميع الإعلانات المطابقة لمعاييرك عبر المواقع |
| بيانات تدريب لنماذج التعلم الآلي | علماء البيانات | بناء نماذج التنبؤ بالرواتب من البيانات التاريخية |
تؤكد أبحاث Hiring Lab الخاصة بـ Indeed ذلك من خلال أن بيانات الإعلانات الوظيفية تتتبع عن قرب بيانات BLS JOLTS ويمكن أن تعمل كمؤشر شبه فوري على حالة سوق العمل في الولايات المتحدة. تستخدم صناديق التحوط سرعة نشر الوظائف كإشارة بيانات بديلة. وتستخدم فرق الموارد البشرية نطاقات الرواتب المستخرجة لمقارنة التعويضات. كما يبني مسؤولو التوظيف قوائم بالمرشحين المحتملين من الشركات التي توظف بنشاط.
معلومة عملية: بيانات الرواتب في Indeed تتحسن، لكنها لا تزال غير مكتملة. حتى منتصف 2025، تضم نحو 59% من الإعلانات في الولايات المتحدة معلومات راتب، لكن حوالي 22% فقط تعرض رقمًا دقيقًا — والباقي نطاقات. أي تحليل للرواتب مبني على بيانات Indeed يجب أن يضع هذا النقص في الحسبان.
اختيار الطريقة المناسبة لاستخراج Indeed باستخدام Python
لا توجد طريقة واحدة “صحيحة” لاستخراج Indeed. أفضل نهج يعتمد على مستوى مهارتك، وكمية البيانات التي تحتاجها، وكمية الصيانة التي أنت مستعد لتحملها. اختبرتُ الطرق الأربع الرئيسية، وهذه مقارنة بينها:
| المعيار | BS4 + Requests | Selenium | JSON المخفي (window.mosaic) | بدون كود (Thunderbit) |
|---|---|---|---|---|
| الصعوبة | مبتدئ | متوسط | متوسط-متقدم | لا شيء (نقرتان) |
| السرعة | سريعة | بطيئة (تجسيد المتصفح) | سريعة | سريعة (استخراج سحابي) |
| المحتوى المولّد بـ JS | لا | نعم | نعم (بيانات مضمّنة) | نعم |
| مقاومة مكافحة الروبوتات | منخفضة | متوسطة (يمكن اكتشافها) | متوسطة-عالية | عالية (تُدار تلقائيًا) |
| الصيانة عند تغير HTML | عالية (تتكسّر المحددات) | عالية | متوسطة (بنية JSON أكثر ثباتًا) | لا شيء (الذكاء الاصطناعي يتكيّف) |
| الأنسب لـ | نماذج أولية سريعة | الصفحات الديناميكية، والمحتوى المقيد بتسجيل الدخول | البيانات المنظمة على نطاق واسع | غير المطورين، والنتائج السريعة |
هذا الدليل يشرح كل طريقة. إذا كنت مطوّر Python، فستحتاج إلى قراءة أقسام BS4 وJSON المخفي وSelenium. وإذا لم تكن مبرمجًا (أو سئمت ببساطة من تصحيح أخطاء 403)، فتجاوز إلى قسم Thunderbit.
قبل أن تبدأ
- مستوى الصعوبة: من مبتدئ إلى متوسط (أقسام Python)؛ لا شيء (قسم Thunderbit)
- الوقت المطلوب: نحو 20–60 دقيقة لإعداد Python وأول عملية استخراج؛ نحو دقيقتين مع Thunderbit
- ما تحتاجه: Python 3.9+، ومحرر أكواد، ومتصفح Chrome، و(للمسار بدون كود) ملحق Thunderbit لمتصفح Chrome
إعداد بيئة Python لاستخراج Indeed
قبل كتابة أي كود للاستخراج، جهّز بيئتك أولًا.
تثبيت المكتبات المطلوبة
أنشئ بيئة افتراضية وثبّت الحزم التي ستحتاجها:
python -m venv indeed_env
source indeed_env/bin/activate # على Windows: indeed_env\Scripts\activate
# لنهج HTTP + التحليل
pip install requests beautifulsoup4 lxml httpx
# لنهج JSON المخفي (الموصى به)
pip install curl_cffi parsel tenacity
# لنهج أتمتة المتصفح
pip install selenium
بعض الملاحظات:
curl_cffiهو الخيار الافتراضي في 2026 لاستخراج المواقع المحمية بـ Cloudflare. فهو ينتحل بصمات TLS الحقيقية للمتصفح، وهو ما لا تستطيع فعلهrequestsوhttpxالتقليديتان. سنشرح أهمية ذلك أكثر في قسم مكافحة الروبوتات.- يأتي
Selenium 4.6+مع Selenium Manager، لذا لم تعد بحاجة إلى تنزيل ChromeDriver يدويًا — إذ تتم إدارة ملف المتصفح تلقائيًا. - استخدم
lxmlكخلفية تحليل لـ BeautifulSoup. فهو أسرع بنحو 1.5x منhtml.parserالقياسي.
إنشاء هيكل المشروع
اجعل الأمر بسيطًا:
indeed_scraper/
├── scraper.py
├── requirements.txt
└── output/
كل أمثلة الأكواد أدناه مبنية على scraper.py.
كيفية استخراج Indeed باستخدام Python عبر BeautifulSoup
هذا هو النهج المناسب للمبتدئين: استخدم requests لجلب الصفحة وBeautifulSoup لتحليل HTML. إنه الأسرع في الإعداد، لكنه أيضًا الأكثر هشاشة على Indeed.
الخطوة 1: بناء رابط بحث Indeed
روابط البحث في Indeed تتبع نمطًا متوقعًا:
https://www.indeed.com/jobs?q=<query>&l=<location>&start=<offset>
على سبيل المثال، للبحث عن "data analyst" في "Austin, TX" بدءًا من الصفحة الأولى:
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 النتائج على دفعات من 10، مع حد أقصى ثابت يبلغ 1,000 نتيجة (start <= 990). أي قيمة offset أعلى من 990 تعيد الصفحة نفسها بصمت.
الخطوة 2: إرسال طلب HTTP برؤوس مناسبة
يحظر Indeed الطلبات التي تستخدم سلاسل User-Agent الافتراضية في Python فورًا. تحتاج إلى رؤوس واقعية:
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)
إذا حصلت على 200، فأنت داخل — مؤقتًا. إذا حصلت على 403، فهذا يعني أن Cloudflare كشفك. (سنشرح كيف تتعامل مع ذلك لاحقًا.)
الخطوة 3: تحليل قوائم الوظائف من HTML
استخدم BeautifulSoup لاختيار عناصر بطاقات الوظائف. استهدف سمات data-testid — فهي أكثر ثباتًا من أسماء CSS العشوائية في 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"Found {len(jobs)} jobs")
الخطوة 4: التعامل مع الترقيم الصفحي
كرّر الصفحات عبر زيادة قيمة start:
import time, random
all_jobs = []
for page in range(0, 50, 10): # أول 5 صفحات
params["start"] = page
url = f"https://www.indeed.com/jobs?{urlencode(params)}"
response = requests.get(url, headers=headers, timeout=30)
# ... التحليل كما سبق ...
all_jobs.extend(jobs)
time.sleep(random.uniform(3, 6))
حدود هذا النهج
سأكون صريحًا: BS4 + Requests هو أضعف أسلوب لـ Indeed في 2026. فـrequests التقليدي يستخدم مكتبة TLS المعيارية في Python، ما ينتج بصمة JA3 يتعرّف عليها Cloudflare فورًا على أنها "ليست متصفحًا." كما أنه لا يدعم HTTP/2، وهو ما يستخدمه Indeed. على الأرجح ستُحجب بعد بضع صفحات. أما محددات CSS؟ فإن Indeed يبدّل أسماء الفئات مثل css-1m4cuuf وjobsearch-JobComponent-embeddedBody-1n0gh5s بشكل متكرر — لذلك فإن أي محدد يستهدفها هو قنبلة موقوتة.
استخدم هذه الطريقة للنماذج الأولية السريعة في صفحة واحدة. أما لأي شيء على نطاق واسع، فاستعمل نهج JSON المخفي.
كيفية استخراج Indeed باستخدام Python عبر بيانات JSON المخفية
هذه هي الطريقة التي أوصي بها لمعظم مطوري Python. بدلًا من تحليل عناصر HTML الهشة، تستخرج بيانات منظمة من متغير JavaScript مضمّن في مصدر صفحة Indeed: window.mosaic.providerData["mosaic-provider-jobcards"].
كل حقل يهمك — المسمى الوظيفي، الشركة، الموقع، الراتب، مفتاح الوظيفة، تاريخ النشر، مؤشر العمل عن بُعد — موجود بالفعل في كتلة JSON هذه. لا حاجة لتنفيذ JavaScript. وقد بقي المخطط مستقرًا منذ 2023 على الأقل, ما يجعله أكثر صمودًا بكثير من محددات DOM.
الخطوة 1: جلب HTML للصفحة
استخدم curl_cffi بدلًا من requests — فهو ينتحل بصمات TLS الحقيقية للمتصفح، وهو أمر حاسم لتجاوز 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))
لماذا curl_cffi؟ لأنه واجهة Python فوق curl-impersonate، والذي يعيد إنتاج ClientHello في TLS، وإطار HTTP/2 SETTINGS، وترتيب الرؤوس كما تفعل المتصفحات الحقيقية بالضبط. وهو عميل HTTP الوحيد في Python الذي ما يزال يُصان بنشاط ويكسر كلًا من JA3/JA4 وبصمة Akamai H2 في استدعاء واحد. وتشمل أهداف الانتحال المدعومة chrome120 وchrome124 وchrome131 وSafari وEdge.
الخطوة 2: استخراج JSON باستخدام تعبير منتظم
كتلة JSON مضمّنة داخل وسم <script>. استخرجها باستخدام 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"Found {len(results)} jobs in hidden JSON")
else:
print("لم يتم العثور على JSON المخفي — قد يكون هناك حظر أو تغيّر في الصفحة")
الخطوة 3: تحليل حقول الوظائف من JSON
كل عنصر في results يحتوي على بيانات أكثر مما يظهر على الصفحة:
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 تقديرات للرواتب، وسمات تصنيفية (وسوم المهارات)، وتقييمات الشركات التي لا تظهر دائمًا في HTML المعروض.
الخطوة 4: استخراج عدة صفحات
استخدم tierSummaries في JSON لفهم إجمالي النتائج، ثم كرر:
import time, random
all_jobs = []
for start in range(0, 50, 10): # أول 5 صفحات
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)} jobs scraped")
لماذا JSON المخفي أكثر صمودًا؟
بنية window.mosaic.providerData تتغير أقل بكثير من أسماء فئات CSS. تحصل على بيانات منظمة ونظيفة دون تحليل HTML فوضوي. ومع ذلك، ما تزال بحاجة إلى تخفيف حدة مكافحة الروبوتات (الرؤوس، التأخيرات، البروكسيات) — وهو ما سنغطيه لاحقًا.
كيفية استخراج Indeed باستخدام Python عبر Selenium
Selenium هو نهج أتمتة المتصفح. وهو مفيد عندما تحتاج إلى التفاعل مع الصفحة — مثل النقر على لوحات تفاصيل الوظائف، أو التعامل مع المحتوى المقيد بتسجيل الدخول، أو استخراج الأوصاف التي تُحمَّل ديناميكيًا وغير موجودة في HTML الأولي.
متى تستخدم Selenium بدلًا من عملاء HTTP؟
- يحمّل Indeed بعض المحتوى ديناميكيًا (الوصف الكامل في اللوحة اليمنى)
- تحتاج إلى استخراج صفحات تتطلب حالة جلسة أو تسجيل دخول
- تقوم باستخراج على نطاق صغير حيث لا تكون السرعة حرجة
نظرة سريعة
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") # الوضع المخفي أكثر قابلية للاكتشاف — استخدمه بحذر
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()
القيود
Selenium بطيء — إذ تتطلب كل صفحة تجسيدًا كاملًا للمتصفح. وChrome في الوضع المخفي يمكن اكتشافه بواسطة نظام مكافحة الروبوتات في Indeed (تتحقق Cloudflare من navigator.webdriver، وسلاسل vendor في WebGL، وعدد الإضافات، وغير ذلك). وحتى undetected-chromedriver لا يؤخر الاكتشاف فقط؛ بل لا يمنعه بشكل دائم. وكما في BS4، ستتكسّر محدداتك عندما يحدّث Indeed واجهته.
في معظم الحالات، يمنحك نهج JSON المخفي البيانات نفسها بسرعة أكبر وبصيانة أقل. احتفظ بـ Selenium للحالات الخاصة التي تحتاج فيها فعلًا إلى متصفح.
كيف تتجنب أخطاء 403 عند استخراج Indeed باستخدام Python
هذا هو القسم الأهم. إذا وصلت هنا بعد بحث محبط في Google، فأنت في المكان الصحيح.

لماذا يحظر Indeed أداة الاستخراج لديك؟
يستخدم Indeed Cloudflare Bot Management مع Cloudflare Turnstile — وليس DataDome ولا PerimeterX. وتؤكد الرؤوس ذلك: server: cloudflare، وcf-ray، وملف تعريف الارتباط __cf_bm الخاص بإدارة الروبوتات. تفتش Cloudflare بصمة TLS لديك (JA3/JA4)، وترتيب رؤوس HTTP/2، وأنماط الطلبات، وإشارات سلوك المتصفح. وإذا بدا أيّ منها غير بشري، فستحصل على 403 أو 429 أو 503، أو — في الحالة الأشد خفاءً — على صفحة تحدي Turnstile مع رمز 200 OK بدلًا من بيانات الوظيفة الفعلية.
تدوير User-Agent ورؤوس الطلبات
إن استخدام User-Agent ثابت واحد هو أسرع طريقة للتعرض للحظر. دوّر بين مجموعة من السلاسل الحديثة والواقعية. مهم: حقول الإصدار الفرعي في Chrome ثُبّتت على 0.0.0 منذ تقليص User-Agent — لا تخترع إصدارات فرعية غير صفرية، وإلا ستكتشفك أنظمة مكافحة الروبوتات.
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",
}
وتأكد أيضًا من أن Client Hints في sec-ch-ua تطابق إصدار الـ UA. فوجود sec-ch-ua: "Chrome";v="131" بجوار User-Agent يدّعي Chrome 145 يُعد إنذارًا فوريًا.
أضف تأخيرات عشوائية بين الطلبات
الفواصل الزمنية الثابتة تُكتشف عبر تحليل الأنماط. استخدم اهتزازًا عشوائيًا:
import time, random
# بين كل طلب وآخر
time.sleep(random.uniform(3, 6))
# عند إعادة المحاولة بعد الحظر
def backoff_sleep(attempt):
base = 4
sleep_time = base * (2 ** attempt) + random.uniform(0, 2)
time.sleep(min(sleep_time, 60))
وتشير آراء المصادر ScrapeOps وWebScraping.AI إلى أن 3–6 ثوانٍ بين الطلبات لكل IP هي القاعدة، مع حد أقصى صارم يقارب 100 طلب لكل IP في الجلسة قبل التدوير.
استخدام تدوير البروكسيات
هذا هو العامل الأكبر في النجاح. البروكسيات من مراكز البيانات ضمن نطاقات AWS/GCP تحقق تقريبًا 5–15% فقط على أهداف Cloudflare Enterprise — أي أنها شبه غير مفيدة على Indeed. أما البروكسيات السكنية مع بصمة TLS صحيحة فترتفع نسبة النجاح إلى 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,
)
تسعير البروكسيات السكنية في 2026 يدور تقريبًا حول 4–8.50 دولارات لكل غيغابايت حسب المزوّد ومستوى الالتزام. وبالنسبة إلى Indeed تحديدًا، ابدأ بمجموعة صغيرة ثم وسّعها حسب الحاجة.
التعامل مع رموز الحالة 403 و429 و503 بمرونة
لا تعِد المحاولة بشكل أعمى. فكل رمز حالة يعني شيئًا مختلفًا:
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,
)
# افحص حالة "200 مع تحدٍ" الخادعة
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 — محجوب. يتم تدوير البروكسي، المحاولة {attempt + 1}")
elif r.status_code == 429:
print(f"429 — تم تقييد المعدل. يتم الإبطاء.")
elif r.status_code == 503:
print(f"503 — الخادم مثقل أو يوجد تحدٍ JavaScript.")
backoff_sleep(attempt)
except Exception as e:
print(f"خطأ في الطلب: {e}")
backoff_sleep(attempt)
raise RuntimeError(f"فشل بعد {max_retries} محاولات: {url}")
حالة 200-مع-تحدٍ هي الأصعب. افحص دائمًا نص الاستجابة بحثًا عن cf-turnstile أو Just a moment قبل اعتبار 200 نجاحًا.
البديل الأسهل: دع Thunderbit يتولى مكافحة الروبوتات
للمستخدمين الذين لا يريدون بناء مجموعات بروكسي، أو تدوير رؤوس، أو انتحال بصمات TLS، فإن الاستخراج السحابي في Thunderbit يتكفل بالكابتشا، وتدوير البروكسي، وحمايات مكافحة الروبوتات تلقائيًا. لا حاجة لإعداد بروكسي، ولا لتكوين curl_cffi، ولا لمكتبات حل CAPTCHA. إنه طريق أقل مقاومة عندما تحتاج فقط إلى البيانات.
لماذا تستمر أداة استخراج Indeed في الانهيار؟ وكيف تصلح ذلك
جدار 403 هو الألم الحاد. أما الألم المزمن فهو الصيانة — أدوات الاستخراج التي تعمل اليوم قد تتعطل الأسبوع القادم، وتعيد بصمت بيانات فارغة أو نتائج قديمة.
كيف يكسر Indeed محدداتك
Indeed يدوّر أسماء فئات CSS بشكل عدواني. وتحذرك إرشادات Bright Data بوضوح من أن فئات مثل css-1m4cuuf وcss-1rqpxry "يبدو أنها مُولّدة عشوائيًا — على الأرجح وقت البناء." واختبار A/B يعني أن جلسات مختلفة ترى تخطيطات مختلفة للصفحة. كما يحدث إعادة هيكلة للـ DOM دون إشعار.
قصة JobFunnel تعليمية جدًا. إذ ذكر أحد المساهمين: "تمكن CaptchaBuster بنجاح من تخفيف الكابتشا، وكان سبب فشل استخراج الصفحة [هو] المحددات القديمة في Beautiful Soup." لم تكن الأداة محجوبة — بل كانت تقرأ العناصر الخطأ.
الاستراتيجية: فضّل JSON المخفي على تحليل DOM
كتلة window.mosaic.providerData بقيت مستقرة بنيويًا منذ 2023 على الأقل. ومسار metaData.mosaicProviderJobCardsModel.results[] ما يزال المرجع الأساسي في 2026. محددات DOM تتكسر شهريًا. أما استخراج JSON فيتكسر سنويًا، إن تكسر أصلًا.
الاستراتيجية: استخدم سمات البيانات بدل أسماء الفئات
عندما تضطر إلى لمس DOM، استهدف السمات الوظيفية:
| المحدد | الغرض |
|---|---|
[data-testid="slider_item"] | حاوية كل بطاقة وظيفة |
[data-testid="job-title"] أو h2.jobTitle > a | رابط عنوان الوظيفة |
[data-testid="company-name"] | اسم جهة العمل |
[data-testid="text-location"] | نص الموقع |
data-jk="<jobkey>" على كل بطاقة | أكثر خطاف ثباتًا — لم يتغير منذ 2019 |
أضف فحوصات تأكيد لاكتشاف المحددات القديمة
لا تدع أداة الاستخراج تعمل بصمت مع نتائج صفرية. أضف فحصًا بعد كل جلب:
results = parse_hidden_json(html)
assert len(results) > 0, (
f"أعاد Indeed مجموعة نتائج فارغة عند start={start} — "
"قد يكون هناك حظر أو CAPTCHA أو تغيّر في المحددات. "
f"أول 500 حرف من الاستجابة: {html[:500]}"
)
سجّل أول 500–2000 حرف من الاستجابة الخام عند الفشل. بهذه الطريقة ستعرف فورًا إن كنت حصلت على تحدي Turnstile، أو جدار تسجيل دخول، أو تغيّر في المخطط. شغّل اختبارًا يوميًا بسيطًا على مستوى CI ضد استعلام ثابت (مثل q=python&l=remote) ويتحقق من وجود نتائج غير صفرية.
البديل الذكي بالذكاء الاصطناعي: أدوات لا تنكسر
يقرأ Thunderbit بنية الصفحة من جديد في كل مرة — فهو لا يعتمد على محددات ثابتة أو أنماط regex جامدة. عندما يغيّر Indeed HTML، يتكيّف Thunderbit تلقائيًا. وهذا يعالج مباشرة عبء الصيانة الذي يذكره المستخدمون في المنتديات باعتباره أكبر مصدر إزعاج لديهم. إذا استيقظت يومًا على رسالة في Slack تقول: "الأداة تعيد صفوفًا فارغة مرة أخرى"، فستعرف قيمة ألا تضطر لإصلاحها بنفسك.
استخراج Indeed دون كتابة Python: البديل بدون كود
كل دليل منافس يفترض أنك ستكتب كود Python. لكن بيانات المنتديات تروي قصة مختلفة. يقول المستخدمون أشياء مثل "الأمر صعب جدًا مع الأخطاء المستمرة"، وبعضهم يقترح الاستعانة بشخص على Fiverr فقط للحصول على البيانات. إذا بدا هذا مألوفًا لك، فهذا القسم هو مخرجك.
كيفية استخراج Indeed باستخدام Thunderbit (خطوة بخطوة)
الخطوة 1: ثبّت ملحق Thunderbit لمتصفح Chrome من متجر Chrome. البدء مجاني.
الخطوة 2: انتقل إلى صفحة نتائج البحث في Indeed داخل متصفحك — مثلًا، https://www.indeed.com/jobs?q=data+analyst&l=Austin%2C+TX.
الخطوة 3: انقر على أيقونة Thunderbit في شريط المتصفح، ثم انقر "اقتراح الحقول بالذكاء الاصطناعي". يفحص الذكاء الاصطناعي الصفحة ويكتشف تلقائيًا أعمدة مثل المسمى الوظيفي، الشركة، الموقع، الراتب، رابط الوظيفة، وتاريخ النشر. يمكنك مراجعة الحقول المقترحة وتعديلها — إزالة الأعمدة التي لا تحتاجها، أو إضافة أعمدة مخصصة بوصف ما تريد باللغة العربية البسيطة.
الخطوة 4: انقر "استخراج". يستخرج Thunderbit البيانات من الصفحة ويعرضها في جدول منظم. ستشاهد صفوفًا لإعلانات الوظائف مع الحقول التي ضبطتها.
الإثراء عبر استخراج الصفحات الفرعية
بعد استخراج صفحة القوائم، انقر "استخراج الصفحات الفرعية" ليزور Thunderbit كل صفحة تفاصيل وظيفة على حدة. سيجلب أوصاف الوظائف الكاملة، والمؤهلات، والمزايا، وروابط التقديم — دون أي إعداد إضافي. هذا يعادل كتابة أداة Python ثانية تزور كل رابط /viewjob?jk=<jobkey>، لكنه يتم بنقرة واحدة.
التعامل مع الترقيم الصفحي تلقائيًا
يتعامل Thunderbit تلقائيًا مع الترقيم الصفحي المعتمد على النقر في Indeed. لا حاجة لبناء روابط offset يدويًا أو كتابة حلقات ترقيم صفحي. فهو ينقر بين الصفحات ويجمع النتائج.
التصدير إلى أدواتك المفضلة
صدّر البيانات المستخرجة إلى CSV أو Excel أو Google Sheets أو Airtable أو Notion — مجانًا بالكامل. لا حاجة لكتابة كود csv.writer() أو pandas.to_csv().
متى تستخدم Python ومتى تستخدم Thunderbit
| الحالة | الأداة الأفضل |
|---|---|
| مسارات بيانات مخصصة، وأتمتة مجدولة عبر cron/Airflow | Python |
| دمج داخل قاعدة كود أكبر | Python |
| منطق تحليل مخصص جدًا | Python |
| بحث لمرة واحدة أو تحليل سوق | Thunderbit |
| أعضاء الفريق غير التقنيين يحتاجون إلى البيانات | Thunderbit |
| الحصول على البيانات الآن دون تصحيح أخطاء 403 | Thunderbit |
| إثراء الصفحات الفرعية دون أي إعداد | Thunderbit |
مقارنة الوقت: إعداد Python + تصحيح مكافحة الروبوتات = ساعات إلى أيام (خصوصًا أول مرة). Thunderbit = أقل من دقيقتين لنفس البيانات. لا أقول إن Python خطأ — بل أقول إن الأمر يعتمد على ما تحتاجه.
هل استخراج بيانات Indeed قانوني؟ ما الذي تحتاج إلى معرفته
لا يتناول أي من أدلة استخراج Indeed الأعلى ترتيبًا مسألة القانونية، وهذا أمر مفاجئ بالنظر إلى تكرار سؤال "هل استخراج Indeed قانوني؟" في المنتديات. هذا ليس استشارة قانونية، لكن إليك المشهد العام.
شروط استخدام Indeed
شروط استخدام Indeed (indeed.com/legal) لا تحتوي على بند عام يقول "ممنوع الاستخراج". والمنع الصريح الوحيد للأتمتة هو القسم A.3.5، الذي يحظر "استخدام أي أتمتة أو سكربتات أو روبوتات لأتمتة عملية التقديم عبر Indeed Apply." وهذا مقصور على مسار التقديم، وليس على القراءة السلبية للإعلانات العامة. الأداة الأساسية لتطبيق Indeed هي تقنية — تحديات Cloudflare، وحظر عناوين IP، وبصمات الأجهزة — وليس المحكمة.
سوابق قانونية ذات صلة
أشهر قضية أمريكية في هذا المجال هي hiQ Labs v. LinkedIn. قضت الدائرة التاسعة في أبريل 2022 بأن استخراج البيانات المتاحة للعامة "على الأرجح لا ينتهك CFAA" (قانون الاحتيال وإساءة استخدام الحاسوب). لكن hiQ ثبت لاحقًا تحمّلها مسؤولية خرق العقد لأن موظفيها أنشؤوا ملفات LinkedIn وهمية وقبلوا الشروط.
وبشكل أحدث، أصدرت Meta v. Bright Data (المحكمة الفدرالية الشمالية في كاليفورنيا، يناير 2024) حكمًا أوضح. فقد قرر القاضي Chen أن شروط Facebook وInstagram "لا تمنع استخراج البيانات العامة بعد تسجيل الخروج." ثم سحبت Meta الادعاءات المتبقية طوعًا في الشهر التالي.
ملف robots.txt الخاص بـ Indeed
ملف robots.txt في Indeed يمنع على نطاق واسع /jobs/ و/job/ للمستخدم الافتراضي User-agent: *، لكنه يسمح صراحةً لـ Googlebot وBingbot بالوصول إلى /viewjob? — أي صفحات تفاصيل الوظائف الفردية. كما تُقيَّد بشدة برامج زحف تدريب الذكاء الاصطناعي (GPTBot وCCBot وanthropic-ai). ملف robots.txt ليس ملزمًا قانونيًا في الولايات المتحدة، لكن احترامه يُعد أفضل ممارسة ودليلًا على حسن النية.
إرشادات عملية للاستخراج المسؤول
- استخرج فقط البيانات المتاحة للعامة — لا تسجّل الدخول، ولا تنشئ حسابات وهمية أبدًا
- احترم حدود المعدل: طلب واحد كل 3–6 ثوانٍ لكل IP، وبالتوازي في حدود أرقام أحادية
- لا تعِد نشر البيانات المستخرجة على أنها لوحة وظائف تخصك
- استخدم البيانات للبحث الشخصي أو الداخلي، لا لإعادة البيع التجاري دون إذن
- تخلّص من أي بيانات شخصية لا تحتاجها أو خزّنها مجزأة؛ وضع حد احتفاظ على البيانات القريبة من الشخصية
- إذا كنت تعمل على نطاق واسع أو في الاتحاد الأوروبي/المملكة المتحدة، فاستشر محاميًا — لأن التزامات الشفافية في المادة 14 من GDPR تنطبق على البيانات الشخصية المستخرجة
طيف المخاطر: أتمتة البحث الشخصي عن وظيفة تقع في الطرف المنخفض. أما إعادة البيع التجاري واسع النطاق لبيانات Indeed فتقع في الطرف الأعلى.
الخلاصة وأهم النقاط
استخراج بيانات Indeed باستخدام Python ممكن، لكنه ليس مشروع عطلة نهاية أسبوع تنفذه ثم تنساه. حماية Cloudflare في Indeed، والمحددات المتغيرة، وإجراءات مكافحة الروبوتات العدوانية تعني أنك بحاجة إلى التعامل مع هذا الموضوع بالأدوات الصحيحة والتوقعات الصحيحة.
إليك ما أراه أهم ما خرجتُ به من كل ذلك:
- Indeed هو أغنى مصدر لبيانات سوق العمل على الويب — 350 مليون زائر شهريًا، و130 مليون إعلان — لكنه يقاوم أدوات الاستخراج بشدة.
- استخراج JSON المخفي (
window.mosaic.providerData) هو نهج Python الأكثر صمودًا. المخطط ثابت منذ سنوات، بينما تتكسر محددات CSS كل شهر. curl_cffiمع انتحال المتصفح هو عميل HTTP الافتراضي في 2026 للمواقع المحمية بـ Cloudflare. أماrequestsوhttpxالتقليديان فيُحجبان بسبب بصمة TLS وحدها.- استخدم دائمًا رؤوسًا دوّارة وتأخيرات عشوائية وبروكسيات سكنية لتجنب أخطاء 403. فالبروكسيات من مراكز البيانات شبه عديمة الفائدة أمام Cloudflare Enterprise.
- أضف فحوصات تأكيد حتى تعرف فورًا متى تتكسر المحددات أو عندما تُعرض عليك صفحة تحدي بدل بيانات الوظائف.
- للمستخدمين غير التقنيين أو لأي شخص يريد النتائج بسرعة فقط، يقدّم Thunderbit مسارًا بدون كود ومدعومًا بالذكاء الاصطناعي يتكيف تلقائيًا مع تغييرات الموقع — بلا بروكسيات، بلا تصحيح، بلا صيانة.
إذا أردت تجربة المسار بدون كود، فـThunderbit يوفّر خطة مجانية لتجربته على Indeed دون التزام. وإذا كنت ستسلك مسار Python، فالأكواد أعلاه تمثل نقطة بداية قوية — فقط تذكّر أن مقاومة مكافحة الروبوتات يجب أن تُعامل كأولوية أساسية لا كفكرة لاحقة.
لمزيد من المعلومات حول أساليب وأدوات استخراج الويب، اطلع على أدلتنا حول كيفية استخراج الويب باستخدام Python، وأفضل أدوات استخراج الويب الآلية، واستخراج الويب دون التعرض للحظر. ويمكنك أيضًا مشاهدة الشروحات على قناة Thunderbit على YouTube.
جرّب Thunderbit لاستخراج بيانات Indeed بسرعة أكبر Get Started Free
الأسئلة الشائعة
ما أفضل مكتبات Python لاستخراج Indeed؟
لطلبات HTTP، تُعد curl_cffi الخيار الأقوى في 2026 — فهي تنتحل بصمات TLS الحقيقية للمتصفح، وهو أمر أساسي لتجاوز Cloudflare. ويمثل httpx مع HTTP/2 بديلًا جيدًا للأهداف الأقل حماية. ولتحليل HTML، تظل BeautifulSoup4 مع lxml هي المعيار. ولأتمتة المتصفح، يعمل كل من Playwright (مع playwright-stealth) وundetected-chromedriver، رغم أن كليهما أصبح أكثر قابلية للاكتشاف. أما نهج regex على JSON المخفي (window.mosaic.providerData) فيتجنب الحاجة إلى التحليل الثقيل بالكامل.
لماذا أستمر في الحصول على أخطاء 403 عند استخراج Indeed؟
يستخدم Indeed Cloudflare Bot Management، الذي يفحص بصمة TLS لديك (JA3/JA4)، وترتيب رؤوس HTTP/2، وأنماط الطلبات، وسلوك المتصفح. إذا كنت تستخدم requests التقليدي، فإن بصمة TLS تكشفك فورًا على أنك سكربت Python — ويأتي 403 قبل حتى قراءة رؤوسك. عالج ذلك بالانتقال إلى curl_cffi مع انتحال المتصفح، وتدوير سلاسل User-Agent الواقعية، وإضافة تأخيرات عشوائية (3–6 ثوانٍ)، واستخدام بروكسيات سكنية. وتحقق أيضًا من حالة "200 مع تحدي Turnstile" — وافحص نص الاستجابة بحثًا عن مؤشرات cf-turnstile.
هل يمكنني استخراج Indeed دون كتابة كود؟
نعم. أدوات مثل Thunderbit تتيح لك استخراج قوائم وظائف Indeed ببضع نقرات — ثبّت ملحق Chrome، وانتقل إلى صفحة البحث في Indeed، وانقر "اقتراح الحقول بالذكاء الاصطناعي" ثم "استخراج." يكتشف الذكاء الاصطناعي في Thunderbit تلقائيًا حقولًا مثل المسمى الوظيفي، الشركة، الموقع، والراتب. كما يتعامل تلقائيًا مع الترقيم الصفحي، وإثراء الصفحات الفرعية (أوصاف الوظائف الكاملة)، وحمايات مكافحة الروبوتات. ويمكنك التصدير مجانًا إلى CSV أو Google Sheets أو Airtable أو Notion.
كم مرة يغيّر Indeed بنية HTML الخاصة به؟
Indeed يدوّر أسماء فئات CSS بانتظام (مثل css-1m4cuuf، وسلاسل التجزئة العشوائية) ويعيد هيكلة عناصر DOM دون إشعار. ويعني اختبار A/B أن مستخدمين مختلفين قد يرون تخطيطات مختلفة في الوقت نفسه. نهج JSON المخفي (window.mosaic.providerData) أكثر ثباتًا بكثير — إذ بقي المخطط متسقًا منذ 2023 على الأقل. وعندما تضطر لاستخدام محددات DOM، استهدف سمات data-testid وdata-jk (مفتاح الوظيفة) بدل فئات CSS.
هل استخراج Indeed قانوني؟
استخراج البيانات العامة المتاحة من روابط Indeed بعد تسجيل الخروج من غير المرجح أن يخلق مسؤولية بموجب CFAA في الولايات المتحدة، استنادًا إلى حكم الدائرة التاسعة في hiQ v. LinkedIn (2022) وقرار Meta v. Bright Data (2024). شروط استخدام Indeed تحظر أتمتة عملية التقديم تحديدًا، لا القراءة السلبية للإعلانات العامة. ومع ذلك، استخرج البيانات بمسؤولية دائمًا: لا تسجّل الدخول، لا تنشئ حسابات وهمية، احترم حدود المعدل، لا تعِد نشر البيانات كلوحة وظائف تخصك، وتعامل بحذر مع أي بيانات شخصية (أسماء المجندين، البريد الإلكتروني) وفقًا لـ GDPR/CCPA. وللعمليات التجارية واسعة النطاق، استشر محاميًا.
اعرف المزيد
- كيفية القيام باستخراج الويب دون التعرض للحظر في Python
- استخراج الويب في Python: تجنب الحظر باستخدام استخدام ذكي للبروكسيات
- كيفية كتابة أداة استخراج ويب باستخدام Python من البداية إلى النهاية
- كيفية استخراج البيانات من موقع ويب باستخدام Python بكفاءة
- كيفية استخراج البيانات باستخدام Python: دليل للمبتدئين


