eJobs.ro Job Listings Scraper avatar

eJobs.ro Job Listings Scraper

Pricing

from $1.10 / 1,000 ejobs.ro job listings scrapers

Go to Apify Store
eJobs.ro Job Listings Scraper

eJobs.ro Job Listings Scraper

Extract Romanian job listings from the public eJobs JSON API, including job taxonomy, company and location metadata, and optional full job descriptions.

Pricing

from $1.10 / 1,000 ejobs.ro job listings scrapers

Rating

0.0

(0)

Developer

Vitalii Bondarev

Vitalii Bondarev

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

6 hours ago

Last modified

Share

eJobs.ro Scraper

Scrape public job listings from eJobs Romania.

This actor reads the public api.ejobs.ro JSON API with Python curl_cffi. It does not launch or control a browser, does not use Playwright or Selenium, and does not scrape the Cloudflare-protected eJobs website or its HTML pages. All job and taxonomy data comes from public JSON API responses.

What it collects

The actor can collect listing-level job data such as:

  • Job ID, title, URL, and publication dates
  • Company name and company identifiers
  • City, county, country, and remote/work-model information
  • Employment type, career level, and domain/category data
  • Salary information when published by the employer
  • Listing description data
  • Optional full detail data from the public job-detail API endpoint
  • Normalized taxonomy values for locations, domains, job types, career levels, and work models

Each job is stored as one dataset record.

Quick start

Use a minimal input to collect jobs matching a search phrase:

{
"search": "python developer",
"maxItems": 50
}

To fetch the richer job-detail response for every collected job:

{
"search": "python developer",
"maxItems": 50,
"fetchDetails": true
}

To search and apply local filters:

{
"search": "developer",
"maxItems": 100,
"fetchDetails": true,
"filters": {
"locations": ["București"],
"jobTypes": ["Full time"],
"careerLevels": ["Mid-Level"],
"remoteOnly": true
}
}

Main input

InputTypeDescription
searchstringSearch phrase sent to the public eJobs API where supported. Use an empty value to browse available jobs without a text query.
maxItemsintegerMaximum number of matching job records to emit. This is a record limit, not a page limit.
startPageintegerOptional API page from which to begin pagination. Pagination normally starts at page 1.
maxPagesintegerOptional maximum number of API pages to request. Use this to put an additional bound on a broad search.
fetchDetailsbooleanWhen true, request the public detail endpoint for each matched job and enrich the listing record with available detail data.
filtersobjectOptional client-side filters applied to normalized listing data. See Client-side filters.
proxyConfigurationobjectOptional Apify Proxy configuration. If omitted, the actor uses a Romanian RESIDENTIAL proxy configuration by default.

The actor accepts normal Apify proxy settings. Supplying a custom proxy configuration overrides the default Romanian residential proxy selection.

Proxy behavior

The default network configuration uses an Apify RESIDENTIAL proxy with Romanian routing.

Romanian residential routing is the default because eJobs is a Romanian job board and API behavior may differ by region. A proxy is still an HTTP transport setting only: the actor calls the JSON API directly and does not attempt to visit or bypass the Cloudflare-protected website.

Client-side filters

The API search response can be broad or incomplete for some combinations of criteria. For predictable results, the actor applies the following filters locally after normalizing each listing.

There are no hidden client-side filters beyond the fields listed below.

Filter fieldAccepted valueBehavior
includeKeywordsstring or array of stringsKeeps jobs whose searchable text contains the supplied keyword values. Searchable text includes title, company, location labels, and available description text.
excludeKeywordsstring or array of stringsRejects jobs whose searchable text contains any excluded keyword.
includeCompaniesstring or array of stringsKeeps jobs whose company name matches one of the supplied company values.
excludeCompaniesstring or array of stringsRejects jobs whose company name matches an excluded value.
locationsstring or arrayKeeps jobs matching one or more normalized location names or location IDs.
countiesstring or arrayKeeps jobs matching one or more Romanian county names or IDs when county data is available.
domainsstring or arrayKeeps jobs matching one or more normalized job domains/categories or their IDs.
jobTypesstring or arrayKeeps jobs matching one or more normalized employment types, such as full-time, part-time, internship, or contract values exposed by the API.
careerLevelsstring or arrayKeeps jobs matching one or more normalized career levels.
workModelsstring or arrayKeeps jobs matching one or more normalized work models, such as onsite, hybrid, or remote when supplied by eJobs.
remoteOnlybooleanWhen true, keeps only jobs marked as remote or having a remote work model.
salaryMinnumberKeeps jobs whose published salary range can satisfy the requested minimum salary. Jobs without usable salary data do not match this filter.
salaryMaxnumberKeeps jobs whose published salary range can satisfy the requested maximum salary. Jobs without usable salary data do not match this filter.
salaryCurrencystringRestricts salary matching to the supplied currency code when salary data includes a currency.
withSalarybooleanWhen true, keeps only jobs with published salary data. When false, keeps only jobs without published salary data.
postedAfterISO date or datetime stringKeeps jobs published on or after the supplied value.
postedBeforeISO date or datetime stringKeeps jobs published on or before the supplied value.

Filter matching rules

  • Text matching is case-insensitive.
  • A list within one filter is treated as an OR condition. For example, locations: ["București", "Cluj-Napoca"] accepts either location.
  • Different filter groups are combined with AND. A job must satisfy every supplied filter group.
  • Exclusion filters take precedence over inclusion filters.
  • Taxonomy filters can use normalized names or IDs when those IDs are available in the API taxonomy.
  • maxItems is applied after client-side filtering. The actor continues paginating until it has emitted the requested number of matching jobs or there are no more results.

Example:

{
"search": "software engineer",
"maxItems": 100,
"filters": {
"includeKeywords": ["python", "backend"],
"excludeKeywords": ["senior"],
"locations": ["București", "Cluj-Napoca"],
"jobTypes": ["Full time"],
"careerLevels": ["Mid-Level"],
"withSalary": true
}
}

Taxonomy normalization

eJobs API responses may contain internal IDs, labels, partial objects, or differently shaped values depending on the endpoint. The actor resolves these into consistent taxonomy fields where possible.

Taxonomy is fetched once per run and reused for all listing and detail records in that run. It is not fetched separately for every job.

Representative normalized taxonomy fields include:

Output fieldDescription
locationsNormalized location objects and/or labels associated with the job.
locationIdsAPI location identifiers when available.
citiesCity names derived from the job location data.
countiesCounty names or identifiers when exposed by the API.
domainsNormalized job domain/category objects or labels.
domainIdsAPI domain/category IDs when available.
jobTypesNormalized employment-type labels and IDs.
careerLevelsNormalized career-level labels and IDs.
workModelsNormalized work-model values, including remote, hybrid, or onsite where supplied.
isRemoteBoolean remote indicator derived from the available API data.

The actor preserves useful listing-level values even when a taxonomy item cannot be resolved. Taxonomy labels should be treated as values supplied by eJobs and may change over time.

Optional detail fetching

Set fetchDetails to true to request the public job-detail API response for each matched listing.

Detail responses can provide richer information than the listing feed, including fuller descriptions, application information, salary details, employer data, or additional job metadata when eJobs exposes them.

The actor deliberately treats a failed detail request as non-fatal:

  1. The job is first collected from the listing API.
  2. The actor attempts the individual detail request when fetchDetails is enabled.
  3. If that detail request succeeds, available detail values enrich the record.
  4. If an individual detail request fails, the actor still emits the job using the listing data.

A failed individual detail request therefore does not discard an otherwise valid listing and does not stop the rest of the run.

Description fields

When description content is available, the actor exposes both markup and readable text forms:

FieldDescription
descriptionHtmlDescription markup supplied by the public API. Preserve this field when formatting and links matter.
descriptionTextPlain-text version of the description for search, analysis, exports, and language processing.
shortDescriptionShorter listing-level summary when supplied separately by the API.

If fetchDetails is disabled, description fields may be limited to what is present in the listing response. With detail fetching enabled, the actor uses the richer detail description when it is available.

Pagination

The actor paginates through the public eJobs listing API.

Pagination behavior:

  • Pages are requested in ascending order, beginning with startPage or page 1.
  • The actor stops after maxItems matching records have been emitted.
  • If maxPages is set, the actor also stops after that many requested pages.
  • The actor stops when the API has no additional results, returns an empty page, or indicates the end of the result set.
  • Client-side filters are evaluated for every listing before it counts toward maxItems.
  • Repeated job IDs are de-duplicated where possible so the same job is not intentionally emitted multiple times during one run.

A broad query with restrictive local filters may require more API pages than the number of records ultimately emitted.

Representative output

The exact set of fields depends on the API response and whether detail fetching is enabled. A representative record can contain fields like the following:

{
"id": "job-id",
"title": "Python Developer",
"url": "https://www.ejobs.ro/user/locuri-de-munca/python-developer/...",
"companyName": "Example Company",
"companyId": "company-id",
"locations": [
{
"id": "location-id",
"name": "București"
}
],
"cities": ["București"],
"counties": ["București"],
"domains": [
{
"id": "domain-id",
"name": "IT Software"
}
],
"jobTypes": ["Full time"],
"careerLevels": ["Mid-Level"],
"workModels": ["Hybrid"],
"isRemote": false,
"salary": {
"min": 8000,
"max": 12000,
"currency": "RON"
},
"publishedAt": "2025-01-01T10:00:00Z",
"expiresAt": "2025-01-31T23:59:59Z",
"descriptionHtml": "Description markup returned by the API",
"descriptionText": "Readable job description text",
"detailFetched": true,
"scrapedAt": "2025-01-01T12:00:00Z"
}

Common fields include:

FieldDescription
idStable eJobs job identifier when provided.
titleJob title.
urlPublic job URL when available.
companyNameEmployer name.
companyIdEmployer identifier when available.
locations, cities, countiesNormalized geographic information.
domains, jobTypes, careerLevels, workModelsNormalized taxonomy values.
isRemoteDerived remote-work indicator.
salaryPublished salary range and currency when available.
publishedAt, expiresAtJob publication and expiry timestamps when supplied.
descriptionHtmlAPI-provided description markup.
descriptionTextPlain-text description.
detailFetchedIndicates whether the job-detail request successfully enriched the listing.
scrapedAtTimestamp at which the actor processed the record.

Fields can be absent or null when eJobs does not provide the corresponding information.

Free-plan preview

On the Apify free plan, the actor provides a preview of up to 10 job records.

The 10-record free-plan preview is a plan limit. It is not a pagination setting and it does not change the actor’s filtering or normalization behavior. A request with a larger maxItems value can still be constrained by the record availability allowed by the current Apify plan.

Pricing and PPE charging

The actor charges one PPE for each successfully emitted job record.

A job record is chargeable only after it has been successfully produced and emitted to the dataset. API requests, taxonomy loading, empty pages, failed detail requests, filtered-out listings, and jobs that are not emitted do not create a job-record PPE charge.

When fetchDetails is enabled, a successful detail request does not create a second PPE charge for the same job. The unit is one successfully emitted job record.

Local fixture test

The repository includes a fixture-based test for validating parsing and normalization without relying on the live eJobs API.

Install the project dependencies, then run:

python -m pytest -q

The fixture test should use saved API payloads from the test fixtures and should not require a browser, a live eJobs account, or access to the Cloudflare-protected website. This makes it suitable for local development and regression testing when the public API is unavailable or rate-limited.

Limitations

  • The actor depends on public api.ejobs.ro responses. The API is controlled by eJobs and can change without notice.
  • Only jobs and fields exposed by the public API can be collected.
  • The actor does not access private employer data, authenticated user data, application submissions, or hidden jobs.
  • Listing data can be incomplete. Salary, work model, county, company metadata, dates, and descriptions are not guaranteed for every job.
  • Detail fetching can improve data quality but is not guaranteed. If an individual detail request fails, the actor falls back to the listing data for that job.
  • A job can disappear, expire, or change while a paginated run is in progress.
  • Taxonomy labels and IDs can be added, removed, renamed, or returned inconsistently by the upstream API.
  • Salary values may use different currencies, ranges, gross/net conventions, or free-form employer text. Salary filtering only works when values can be interpreted reliably.
  • Public API availability, rate limits, regional behavior, proxy availability, and network failures can affect throughput and completeness.
  • This actor is designed for job-data collection and analysis. Users remain responsible for complying with applicable laws, eJobs terms, privacy obligations, and Apify platform rules.