Use Bayt.com MENA Job Listing & Salary Scraper with Python
Search Bayt.com job listings across Middle East and North Africa countries by keyword, location, career level, and employment type. Get titles, companies, locations, salaries, required skills, full descriptions, and apply links.
1. Choose the data you need
Review the published README for supported collection modes, examples, and limits. The recipe below uses the current published input definition.
2. Prepare a source-based input
This JSON contains published prefills and required-field defaults. Review every value for your task before running it; it is not a promise of successful collection.
{
"careerLevel": "any",
"companyUrls": [],
"country": "uae",
"datePosted": "any",
"easyApplyOnly": false,
"employmentType": "any",
"includeCompanyJobs": false,
"includeDetails": false,
"industry": "any",
"jobIds": [],
"maxItems": 2,
"maxPages": 1,
"mode": "search",
"remoteOnly": false,
"searchQueries": [
"accountant"
],
"sortBy": "date",
"startUrls": []
}
Download input.example.json and save your reviewed copy as input.json.
| Field | Type | Required | Description |
|---|---|---|---|
mode | string | optional | What to scrape. Search jobs builds one Bayt search per query. Paste URLs accepts job, search or company links. Job IDs resolves specific postings. Company pulls a profile and its open roles. |
searchQueries | array | optional | One keyword per entry, for example accountant or software engineer. Several entries are searched in order and duplicates are removed. |
country | string | optional | Bayt market to search. Pick International for every country, or choose one of the 24 supported markets. |
city | string | optional | Optional city name such as Dubai, Riyadh or Cairo. If Bayt has no page for the city, the search falls back to the whole country. |
employmentType | string | optional | Filter by the employment type Bayt publishes for the job. |
careerLevel | string | optional | Filter by seniority. Bayt publishes this for some jobs, mostly employer postings. |
datePosted | string | optional | Only return jobs Bayt marks as posted within this window. |
sortBy | string | optional | Newest first is best for monitoring. Most relevant is best for broad keyword research. |
industry | string | optional | Filter by one of Bayt's employer industries. |
companyName | string | optional | Optional employer name filter, for example Al Futtaim or Infosys. Bayt matches the employer facet, so partial names may work differently from exact names. |
remoteOnly | boolean | optional | Use Bayt's server-side remote-working filter. |
easyApplyOnly | boolean | optional | Only return jobs that accept an application directly on Bayt. |
minSalary | integer | optional | Exclude jobs whose published USD monthly range ends below this amount. Jobs with no published salary are excluded when this is set. |
includeDetails | boolean | optional | On: full descriptions, skills, preferred-candidate criteria, parsed salary and company metadata. Off: faster, listing-card fields only. |
maxItems | integer | optional | Overall record limit for the run. Bayt exposes at most about 10,000 results per single search. |
maxPages | integer | optional | Safety cap on listing pages per search. Bayt shows 30 jobs per page and stops near 10,000 results. |
startUrls | array | optional | Job, search or company URLs, used when Mode is Paste URLs. Arabic and English Bayt URLs are accepted. |
jobIds | array | optional | Bayt job IDs such as 5498312, or full job URLs, used when Mode is Resolve job IDs. |
companyUrls | array | optional | Bayt company profile URLs or numeric company IDs, used when Mode is Company profile. |
includeCompanyJobs | boolean | optional | In Company mode, also return the company's open roles as job records. |
3. Start an Actor run
Set APIFY_TOKEN in your environment. Python 3.10 or newer is sufficient; this recipe uses no third-party packages.
Execution may incur charges. Review current pricing on Apify. The request asks for a 120-second timeout and a charge limit; these settings are subject to Apify’s pricing and do not guarantee an all-inclusive spending cap.
import json
import os
import urllib.request
# Save the schema-derived example as input.json; review and edit it first.
with open("input.json", encoding="utf-8") as stream:
actor_input = json.load(stream)
token = os.environ["APIFY_TOKEN"]
request = urllib.request.Request(
"https://api.apify.com/v2/acts/Q4xXkQSUwkQkVnB7E/runs?timeout=120&maxTotalChargeUsd=0.50",
data=json.dumps(actor_input).encode("utf-8"),
headers={"Authorization": "Bearer " + token, "Content-Type": "application/json"},
method="POST",
)
# This starts a potentially billable run. Do not automatically retry this POST.
with urllib.request.urlopen(request, timeout=40) as response:
run = json.load(response)["data"]
print("Run ID:", run["id"])
print("Status:", run["status"])
# Inspect and download results in Apify Console once the run succeeds.
4. Inspect the actual results
Open the run in Apify Console and wait for a successful completion. Use the published output schema to locate results and the dataset schema to understand declared views. Missing or optional record fields must not be treated as guaranteed values.
Bayt.com job records with salary, location, company, requirements and provenance, plus company profiles when Company mode is used.
Questions before you run
Which inputs are required?
No top-level fields are marked required in the published schema. Conditional requirements can still apply; check the README.
What does this guide verify?
The fields, prefills, and schema links are rendered from the published build. This is a usage recipe, not a paid live extraction test. Source availability and collection results can vary.
What if the run request times out?
Check Apify Console before retrying. The first request may already have created a run. Do not automatically repeat a run-creation POST.
Generated from source build dmkWw6R5TxYj7Fdkk and its README and schemas. Source changes regenerate this guide; no third-party editorial claims are inferred.