PracticeMatch Physician & Healthcare Jobs Scraper
Pricing
from $2.00 / 1,000 jobs
PracticeMatch Physician & Healthcare Jobs Scraper
Scrape all 40,900+ physician, advanced-practitioner and healthcare jobs on PracticeMatch. Real salary ranges on about half the board, O*NET specialty codes and mappable coordinates. HTTP-only, no browser, no proxy.
Pricing
from $2.00 / 1,000 jobs
Rating
0.0
(0)
Developer
Piquno
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
13 days ago
Last modified
Categories
Share
Every one of the 40,900+ physician, advanced-practitioner and healthcare jobs on PracticeMatch.com — with the salary range, which 10 of the 12 most recent postings published.
Most job boards withhold pay. Physician recruiting does not. On a live run of the newest 12 postings, 10 carried a real pay range — for example an Orthopedic Surgeon at $650,000–$750,000/year, Obstetrics & Gynecology at $439,296–$486,245/year, and a Hospitalist at $173–$213/hour. That is the point of this actor. Every posting also carries its O*NET SOC code, so specialties join cleanly to BLS wage data instead of needing string matching.
HTTP-only. No browser, no proxy, no login.
What you get
One flat row per posting — no nested objects or arrays, so CSV and Excel exports are clean.
| Field | What it is |
|---|---|
jobId, jobUrl, profession | Stable id, canonical URL, and which of the three boards it came from |
title, description, descriptionHtml | Posted title and the full posting, as text and as original HTML |
employerName, employerUrl | Hiring organisation and its own website |
specialty, socCode, specialtySlug | "Family Medicine Physicians", 29-1215.00, and the URL slug |
salaryMin, salaryMax, salaryPeriod, salaryCurrency, salaryDisclosed | The published range and whether there is one at all |
streetAddress, locationCity, locationState, locationPostalCode, locationCountry | Full address |
latitude, longitude | Coordinates where the posting carries them |
employmentType, directApply | FULL_TIME / PART_TIME / etc, and whether it is a direct-apply listing |
datePosted, datePostedRaw, validThrough | Normalised to UTC, plus the site's original string |
scrapedAt, fieldsPopulated | When the row was taken, and how many of its fields are non-null |
Measured fill rates
Measured on two live 12-posting runs on 2026-08-23 — counted, not estimated. Salary disclosure depends heavily on how recent a posting is, so both ends are given:
| Field | Fill |
|---|---|
jobId, jobUrl, title, description | 100% |
employerName, employerUrl, specialty, specialtySlug | 100% |
locationCity, locationState, locationCountry, datePosted | 100% |
socCode | 92% |
locationPostalCode, employmentType | 83% |
streetAddress, latitude, longitude | 58% |
salaryMin, newest postings (the default) | 83% |
salaryMin, oldest postings on the board | 42% |
salaryMax | 33–75% — some postings publish a floor with no ceiling |
validThrough | 0% — the site does not publish expiry dates |
Nothing is ever invented to fill a gap: a field the site did not publish stays null. A salary published as a bare minimum keeps salaryMax null rather than copying the floor into it.
Coverage
The sitemap is the only complete index, and it is split across three shards. All figures below were counted, not estimated:
| Board | Postings | URL shape |
|---|---|---|
| Physicians | 32,528 | /physicians/job-details.cfm/{id}/... |
| Advanced practitioners | 8,376 | /advanced-practitioners/job-details.cfm/{id}/... |
| Healthcare | 546 | /healthcare/jobs/job-details/{id} |
| Total | 40,903 distinct job ids |
The site's paged browse pages cannot reach all of this, which is why seeding is done from the sitemap.
Input
{"professions": ["physician"],"specialtyContains": "Family Medicine","locationState": "Texas","withSalaryOnly": true,"maxJobs": 500}
Defaults: maxJobs is 12 and requestDelaySecs is 5 — a quick sample that finishes in about 90 seconds. Raise maxJobs for a real extract and budget the time (see below).
locationState takes either TX or Texas. startUrls accepts PracticeMatch job-details URLs directly and overrides the board selection. newestFirst is on by default and walks the board from the most recently created postings backwards.
Speed, and the trade-off you should understand
Read this before your first big run. PracticeMatch publishes Crawl-Delay: 5 in its robots.txt, and this actor honours it by default. Each job is one request, so:
requestDelaySecs | Throughput | 1,000 jobs takes |
|---|---|---|
| 5 (default, what the site asks for) | ~720 jobs/hour | ~1h 25m |
| lower | faster | your call, and your blocking risk |
requestDelaySecs is adjustable. Lowering it departs from what the site asks for, and that is your decision rather than the default. A full 40,900-job extract at the default delay is a multi-day run — most buyers want a specialty or a state, not the whole board.
Monitoring the board
Set incremental: true with its own stateKey. Only postings not seen before are emitted, tagged changeType: "new", so a daily watch bills for the handful that are actually new rather than re-billing everything.
Filters are applied before billing
titleContains, specialtyContains, locationState, employmentType, withSalaryOnly and postedWithinDays all run before a row is charged. You are never billed for a row a filter excluded.
Limitations — read before you buy
- Salary disclosure tracks recency. 10 of the newest 12 postings published a range; only 5 of the oldest 12 did. With the default
newestFirstyou are on the good end of that, but disclosure is never universal — usewithSalaryOnlywhen you need it. - The board carries stale postings, and this is the thing to know before buying. The sitemap still lists jobs dated as far back as 2007. Walking it forwards, only 1 of the first 12 postings was from the past year. This actor therefore defaults to
newestFirst: true, which starts from the most recently created listings — butdatePostedis not a clean proxy for freshness either, because it records the original posting date and survives re-listing. If you need a live-market view, setpostedWithinDays. Without it you are getting the archive along with the active board. - Some sitemap entries are dead. Taken-down jobs answer with a redirect and an empty body. Those are counted in the run summary as
deadOrUnparseableListingsand are never charged — you only pay for postings that actually returned content. validThroughis not published. The column exists and is honest about being empty rather than being filled with a guess.- US only. PracticeMatch is a US physician recruiting board.
- Coordinates are partial. Present on much of the physician board, mostly absent on the other two.
- Format risk. Rows are built from each page's JSON-LD
JobPosting, which parsed cleanly on 100% of sampled pages. If the site changes format the actor logs it and skips the row rather than silently emitting a blank one.
Output
Three ready-made views on the Output tab: Overview (the columns most people export), Compensation (pay only, for salary benchmarking by specialty and state) and Employers & geo (lead lists and territory mapping). A RUN_SUMMARY record in the key-value store reports rows pushed, rows billed, rows filtered out, dead listings and fetch failures.