Quick answer
The HelloWork Jobs Scraper turns hellowork.com searches, by keyword and French city, into a deduplicated table of job offers: title, company, location split into city and department code, contract type (CDI, CDD, Intérim and so on), working time, remote policy, salary text plus parsed minimum, maximum, currency and period, posting date and apply method. HelloWork is a major French jobs board with no public API. Pricing is pay-per-result, $0.20 per run plus $0.002 per job, $2.20 per 1,000 jobs.
Does HelloWork have a public jobs API?
No. The search page is built for browsers, and the structured facts are scattered between visible nodes, an accessible label on each offer link and an analytics attribute. The Actor reads all three, lets the visible nodes win and uses the label to fill gaps, then returns one validated row per offer.
Why is parsing a French salary harder than it looks?
French number formatting breaks naive regexes. Thousands are separated by spaces, and the site uses non-breaking and narrow non-breaking spaces (U+00A0 and U+202F), so 45 000 - 90 000 € / an may not contain a single ordinary space. The decimal separator is a comma, and the period is written in French (an, jour, mois, heure).
A salary like "45 000 - 90 000 € / an" can be separated by narrow no-break spaces, so splitting on a normal space reads 45 and 000 as two numbers.
So we normalise every space variant first, then parse the range into salaryMin and salaryMax (equal for a single value), salaryCurrency (EUR) and salaryPeriod (year, day, month, hour). If the employer discloses nothing, or the text is not numeric, the numbers are null, never 0, and salaryText keeps what the site showed.
What else we handle
- Titles can contain commas. The offer label reads like "title à city, chez company, pour un CDI, ...". We split on the last ", pour un" because the tail segments never contain commas but titles can.
-
Remote versus contract duration. The same tag slot carries "2 ans" (a contract length) and "Télétravail partiel". Only text containing "travail", accent-folded, becomes
remotePolicy. -
Anonymous employers. One paragraph in the heading means no company name, so
companyNameisnullinstead of repeating the title. -
Relative dates. "il y a 5 heures" is kept in
postedTextand converted to an ISOpostedAtfrom the run time. A month counts as 30 days, and "plus de 1 mois" is read as one month back. -
Approximate matches are flagged, not hidden. HelloWork mixes near matches after exact ones;
isApproximateMatchlets you filter either way. - Dedupe by job id, and paging stops using the "Afficher N offres" total, 30 jobs per page.
What the Actor gives you
One row per job, 25 fields, including jobId, title, companyName, location, city, departmentCode, contractType, workingTime, remotePolicy, salaryText, salaryMin, salaryMax, salaryCurrency, salaryPeriod, postedText, postedAt, applyMethod, isSuperRecruiter, isApproximateMatch, url, query, searchLocation and scrapedAt.
{
"jobId": "80459780",
"title": "Python Developer - Paris H/F",
"companyName": "Approach People Recruitment",
"location": "Paris - 75",
"city": "Paris",
"departmentCode": "75",
"contractType": "CDI",
"workingTime": "temps plein",
"remotePolicy": null,
"salaryText": "45 000 - 90 000 € / an",
"salaryMin": 45000,
"salaryMax": 90000,
"salaryCurrency": "EUR",
"salaryPeriod": "year",
"postedText": "il y a 5 heures",
"postedAt": "2026-10-08",
"applyMethod": "UrlWithForm",
"url": "https://www.hellowork.com/fr-fr/emplois/80459780.html",
"query": "python",
"searchLocation": "Paris",
"scrapedAt": "2026-10-08T09:30:00Z"
}
Input: queries (keywords), locations (optional French cities; each query runs once per city, empty means all of France) and maxItems per query and city combination.
Honest limitations 🚧
Listing data only: no full job descriptions, no contract or salary filters, no company pages. isSponsored is best effort, and we have not seen a sponsored card yet. Titles, contract names and remote labels stay in French as the site writes them. A search that finds nothing is a successful run that costs only the start fee.
FAQ
Do I need a HelloWork account or API key?
No.
Why is salary empty on many rows?
Many employers don't disclose pay. We leave it empty rather than returning a misleading 0.
What about blocks and retries?
That's our job. We send browser-grade requests through curl-cffi and retry failed pages with exponential backoff, up to 5 attempts, honouring Retry-After. HelloWork answers without a proxy, so Apify Proxy is off by default and optional.
How does pricing work?
$0.20 per run plus $0.002 per job: $2.20 per 1,000 jobs.
→ HelloWork Jobs Scraper on Apify
Built by Devil Scrapes. We handle the French number formats, the retries and the messy labels, so an empty salary means undisclosed, not zero. 😈
Top comments (0)