跳到正文
DEV Community· Max Prozapas·· 4 小時前AI 評分58

如何毋須無頭瀏覽器,監察任何公司的職位空缺:Workday、Greenhouse、Lever 等 11 種 ATS

How to monitor any company's job openings (Workday, Greenhouse, Lever & 8 more) without a headless browser

AI 導讀

作者示範如何毋須使用無頭瀏覽器,透過 11 種 ATS 的公開資料介面監察多間公司的職位空缺,並統一資料格式。文中列出各系統端點和資料差異,例如 Workday 以 POST 分頁回傳職位,完整端點參考見 github.com/Mersetti/ats-job-board-apis。追蹤新增及關閉職位時,方法以首次執行作靜默基準,並只在公司資料擷取成功後才標記職位關閉。

正文

Want a feed of new openings at a list of companies — for a niche job board, a recruiting pipeline, a hiring-trends dashboard
or just your own job hunt? You don't need Puppeteer. Almost every company publishes jobs through an applicant tracking
system (ATS)
, and every major ATS exposes a public, unauthenticated JSON feed for its career pages.

This post shows the endpoints, the gotchas I hit, and the small amount of code that turns 11 different formats into one.

Step 1: find out which ATS a company uses

Open the careers page and look at the links / embedded scripts:

You see in the HTML ATS
boards.greenhouse.io/stripe Greenhouse
jobs.lever.co/palantir Lever
jobs.ashbyhq.com/openai Ashby
nvidia.wd5.myworkdayjobs.com/NVIDIAExternalCareerSite Workday
apply.workable.com/huggingface Workable
jobs.smartrecruiters.com/BoschGroup SmartRecruiters

…plus Recruitee, Personio, Breezy HR, Teamtailor and Rippling. A regex per pattern over the page HTML detects
most companies automatically.

Step 2: call the public feed

The easy ones return everything in one request:

# Greenhouse (content=true adds descriptions)
curl "https://boards-api.greenhouse.io/v1/boards/stripe/jobs?content=true"

# Lever
curl "https://api.lever.co/v0/postings/palantir?mode=json"

# Ashby (with structured salary!)
curl "https://api.ashbyhq.com/posting-api/job-board/openai?includeCompensation=true"

Workday is the odd one: a POST with a JSON body, 20 jobs per page:

curl -X POST -H "Content-Type: application/json" \
  -d '{"limit":20,"offset":0,"searchText":"engineer","appliedFacets":{}}' \
  "https://nvidia.wd5.myworkdayjobs.com/wday/cxs/nvidia/NVIDIAExternalCareerSite/jobs"

Tip: use searchText — paging through 2,000 NVIDIA jobs to find 30 matching ones is slow; Workday's own search isn't.

Step 3: the gotchas

  • Greenhouse descriptions are double-encoded HTML (<p>) — decode entities first, then strip tags.
  • Workday dates are text: Posted Today, Posted 3 Days Ago, Posted 30+ Days Ago. The detail endpoint has the real startDate. locationsText may literally be "2 Locations".
  • Workday total is only correct on the first page.
  • Recruitee dates look like 2026-10-13 10:58:56 UTC — not ISO.
  • Personio returns XML, and some companies live on .jobs.personio.com instead of .de.
  • SmartRecruiters and Rippling need one detail call per job for descriptions (Rippling even for the date).
  • Teamtailor usually runs on a custom domain — /jobs.rss on the careers domain gives you everything.

Step 4: normalize

Map every source into one shape:

{
  company, ats, jobId, title, department, location, locations, country,
  remote, workplaceType, employmentType, postedAt, salary, descriptionText, applyUrl
}

Salary deserves a note: only Ashby, Lever, Recruitee and Rippling have structured pay. For the rest, US postings
usually state a range in the text, and one regex catches most of them:

const m = /([$€£])\s?(\d{1,3}(?:,\d{3})*|\d+)\s?([kK])?\s?(?:-|–|to)\s?[$€£]?\s?(\d{1,3}(?:,\d{3})*|\d+)\s?([kK])?/.exec(text);

Reject yearly ranges under 10,000 so "$1,000–$2,000 signing bonus" doesn't become a salary. In my tests this finds
pay for roughly half of all jobs.

Step 5: only new jobs

Keep a map of ats:company:jobId → firstSeenAt. Each run:

  • job not in the map → new
  • job in the map but gone now → closed, but only if that company's fetch succeeded (otherwise one timeout looks like a mass closure)
  • make the very first run a silent baseline, so your "new jobs" feed doesn't start with 3,000 items.

Run it daily on a schedule and you have a new-jobs feed for any list of companies.

Full endpoint reference

I documented all 11 endpoints, fields and quirks here:
👉 github.com/Mersetti/ats-job-board-apis

Don't want to maintain it?

I packaged all of the above — 11 ATS, auto-detection from careers URLs, salary extraction, filters and new/closed
monitoring — as an Apify Actor: Career Sites Jobs Feed. Pay per job,
schedule it, export to CSV/Sheets or call it from an AI agent.

Which ATS should I add next? Let me know in the comments.

來源:DEV Community · dev.to