Skip to main content

jobdrop

A multi-source job scraper. Hits 33 job boards in one call, normalizes the results into a pandas DataFrame, and ships with anti-bot handling for the boards that block standard scrapers.

Maintainer: this project is maintained by kbwhodat. Substantially extended from the original cullenwatson/JobSpy (MIT licensed) with new sources, an integrated MCP server, salary/seniority filters, and reliability fixes across all scrapers.

What's in here

33 sources

site_name Source Notes
linkedin LinkedIn Public listings + optional detail-page enrichment
indeed Indeed GraphQL with per-company cap + paginate-until-quota
glassdoor Glassdoor Listings + company reviews + salary data
google Google Jobs SERP aggregation across many sources
zip_recruiter ZipRecruiter US/Canada-focused
hiring_cafe Hiring Cafe AI-curated, ~140 jobs/page with rich tags (seniority, comp, skills, workplace_type)
wellfound Wellfound (formerly AngelList) 50k+ startup roles
collab_work CollabWork Community/newsletter aggregator (~2k curated roles, fastest source)
trueup TrueUp Tech-startup curated. Adds company-trajectory score, valuation, funding stage, layoff/health flags. Pure HTTP, sub-second
greenhouse Greenhouse-hosted boards Most YC and Series A+ companies; 3-layer staleness filter
ashby Ashby-hosted boards OpenAI, Notion, Linear, Ramp, Mercury, Vercel, etc. Google-dorked discovery + GraphQL enrichment
workday Workday tenants Fortune-500-heavy (NVIDIA, Salesforce, Disney, Comcast, JPMorgan, Lockheed, etc.). Google-dorked discovery + CXS API enrichment
lever Lever-hosted boards Plaid, HashiCorp, Kraken, Spotify, etc. Google-dorked discovery + REST enrichment
remoteok RemoteOK Fully-remote jobs aggregator. Single global JSON feed, sub-second response
weworkremotely WeWorkRemotely Fully-remote jobs aggregator. Public RSS feed, currently-live postings only
governmentjobs GovernmentJobs.com (NEOGOV) State/county/city public-sector jobs (non-federal companion to USAJobs). Google-dorked discovery + JSON-LD enrichment
builtin Built In Tech-vetted local job board family (Built In NYC/LA/Chicago/Atlanta/etc.). Cross-source dedup keeps the tech-quality filter without inflating result count
icims iCIMS Multi-tenant ATS (~40+ live tenants per query: Sargent & Lundy, Emory, RS&H, VHB, Constructconnect, etc.). Google-dorked discovery + per-tenant HTML enrichment
bayt Bayt Middle East focused
naukri Naukri India's largest job portal
usajobs USAJobs.gov US federal public API
adzuna Adzuna Public API, 100% salary fill rate
jooble Jooble Public API, 60+ countries
findwork Findwork.dev Developer-focused public API
the_muse The Muse Culture-forward public API
insight_global Insight Global staffing Server-rendered listings
clearance_jobs ClearanceJobs (DHI) Security-cleared roles, full JD + salary + structured job_type
kforce Kforce staffing Direct backend API for fast results
snagajob Snagajob Dominant US hourly / part-time / shift-work board. Retail, food, warehouse, caregiving. Clean public JSON API
dice Dice (DHI) US tech / IT specialty board. SSR'd HTML scrape via Googlebot UA
idealist Idealist Largest US nonprofit / NGO / mission-driven job board. Sitemap-driven + JSON-LD on every detail page
careerbuilder CareerBuilder Broad US/CA general-purpose board. SSR'd HTML with inline jobResults JSON (50 jobs/page). Bypasses Cloudflare WAF via Safari iOS TLS fingerprint
handshake Handshake Early-talent / student / new-grad. Public city-page surface + JSON-LD detail. Most postings auth-walled to verified students; this covers the public slice

Installation

As a Python library

pip install -U jobdrop

Python ≥ 3.10 required.

As an MCP server (Claude Desktop / Claude Code / Cursor / Cline / opencode)

Install the binary once with uv tool install (or pipx install):

uv tool install "jobdrop[mcp]"
# or:  pipx install "jobdrop[mcp]"

Then add to your MCP client config.

Claude Desktop / Claude Code / Cursor / Cline — ~/Library/Application Support/Claude/claude_desktop_config.json (or equivalent):

{
  "mcpServers": {
    "jobdrop": {
      "command": "jobdrop-mcp-server"
    }
  }
}

opencode — ~/.config/opencode/opencode.json (or .opencode/opencode.json in your project):

{
  "mcp": {
    "jobdrop": {
      "type": "local",
      "command": ["jobdrop-mcp-server"],
      "enabled": true
    }
  }
}

That's it — the client launches jobdrop-mcp-server as a stdio subprocess on demand. No daemon, no port.

Note: prefer the uv tool install path so the binary lands in PATH and the client launches it directly — same pattern as reference MCP servers (filesystem, git, etc.).

Usage

from jobdrop import scrape_jobs

jobs = scrape_jobs(
    site_name=["insight_global", "clearance_jobs", "kforce", "greenhouse",
               "linkedin", "indeed", "google"],
    search_term="site reliability engineer",
    location="Atlanta, GA",
    results_wanted=20,
    hours_old=720,          # 30-day freshness cap
    country_indeed="usa",
)
print(f"Found {len(jobs)} jobs")
print(jobs[["site", "title", "company", "location", "min_amount", "max_amount", "job_url"]].head())

Parameters

scrape_jobs(
  site_name              list[str] | str — any of the 28 sources above (default: all)
  search_term            str        — keyword query
  google_search_term     str        — Google Jobs override (only filter for `google`)
  location               str        — "City, ST" or ZIP. Each scraper geocodes its own way.
  distance               int        — radius miles, default 50
  is_remote              bool       — remote-only filter (where supported)
  job_type               str        — "fulltime" | "parttime" | "contract" | "internship"
  easy_apply             bool       — direct-board apply only (where supported)
  results_wanted         int        — per-site target
  offset                 int        — pagination offset
  hours_old              int        — drop postings older than N hours
  country_indeed         str        — Indeed/Glassdoor country (see list below)
  description_format     str        — "markdown" | "html"
  enforce_annual_salary  bool       — convert hourly/monthly to yearly
  linkedin_fetch_description  bool  — full JD + direct URL (slower)
  linkedin_company_ids   list[int]  — filter LinkedIn by company IDs
  proxies                list[str]  — round-robin proxies, "user:pass@host:port"
  ca_cert                str        — CA cert path for proxies
  user_agent             str        — override the default UA
  verbose                int        — 0 errors / 1 warnings / 2 all
)

Per-scraper limitations

  • Indeed — only one of hours_old / (job_type+is_remote) / easy_apply per call.
  • LinkedIn — only one of hours_old / easy_apply per call.
  • ClearanceJobs — location/remote filters require facet IDs from the dropdown endpoints (not implemented). Filter client-side or scope by keyword.
  • InsightGlobal — does not expose client-company name (it's the staffing firm). is_remote is not available in their data.
  • Greenhouse — Google indexes some postings after they're filled. Stale 404s are filtered out; the freshness cutoff filters "live but ancient" postings (default 90 days, override with hours_old).

JobPost schema

JobPost
├── id, title, company_name, company_url, job_url
├── location { country, city, state }
├── description
├── is_remote
├── date_posted
├── job_type        fulltime | parttime | contract | internship
├── compensation
│   ├── interval   yearly | monthly | weekly | daily | hourly
│   ├── min_amount, max_amount, currency
│   └── salary_source
├── job_level                                  (LinkedIn, ClearanceJobs)
├── company_industry                           (LinkedIn, Indeed, Greenhouse, Kforce)
├── company_country, company_addresses,
│   company_employees_label, company_revenue_label,
│   company_description, company_logo          (Indeed)
├── skills, experience_range,
│   company_rating, company_reviews_count,
│   vacancy_count, work_from_home_type         (Naukri)
└── emails

Indeed / Glassdoor country list

Pass country_indeed (use the exact name; * = also supported on Glassdoor):

Argentina Australia* Austria* Bahrain
Belgium* Brazil* Canada* Chile
China Colombia Costa Rica Czech Republic
Denmark Ecuador Egypt Finland
France* Germany* Greece Hong Kong*
Hungary India* Indonesia Ireland*
Israel Italy* Japan Kuwait
Luxembourg Malaysia Mexico* Morocco
Netherlands* New Zealand* Nigeria Norway
Oman Pakistan Panama Peru
Philippines Poland Portugal Qatar
Romania Saudi Arabia Singapore* South Africa
South Korea Spain* Sweden Switzerland*
Taiwan Thailand Turkey Ukraine
United Arab Emirates UK* USA* Uruguay
Venezuela Vietnam*

LinkedIn searches globally and uses only location. ZipRecruiter is US/Canada and uses only location. Bayt searches internationally with only search_term.

Notes

  • Most boards cap a single search at ~1000 results.
  • LinkedIn rate-limits aggressively around the 10th page of pagination on a single IP. Use proxies.
  • For Indeed search-term tuning: it searches the description too. Use -foo to exclude, "exact phrase" for exact match. Example:
    search_term='"site reliability engineer" (kubernetes OR terraform) -recruiter'
    
  • For Google: copy the exact filter syntax from a real Google Jobs search and pass it as google_search_term.
  • For Greenhouse: keyword + location are passed straight to a Google site:greenhouse.io query, so Boolean operators and quotes work. Don't quote the full "City, ST" — quote the city alone, leave the state bare.

License

MIT. See LICENSE.

Metadata

Release files for jobdrop 2.10.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for jobdrop 2.10.0
File Size Uploaded
jobdrop-2.10.0.tar.gz 141.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for jobdrop 2.10.0
File Interpreter ABI Platform
jobdrop-2.10.0-py3-none-any.whl Python 3 none any Details

Total release size: 328.1 kB

Release files / jobdrop-2.10.0.tar.gz

Download URL jobdrop-2.10.0.tar.gz
Size 141.5 kB
Tags Source
SHA-256 checksum
How to use checksums
b2451f0693f79564796230e51f779b552a130831f00e25bdcb0a9f5eff2060d8
BLAKE2b-256 checksum
How to use checksums
d67fd7b222edc982fe5a9efd0ea99fab2e21fcd3673274c441ccb267ecc3597e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.13

Release files / jobdrop-2.10.0-py3-none-any.whl

Download URL jobdrop-2.10.0-py3-none-any.whl
Size 186.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e5edfe15560c4bdf05d8ef37909047b8665682f574610b4c5a6f8ce76cdc5b10
BLAKE2b-256 checksum
How to use checksums
63763032e062b866bf0cc5d1036245dd0119616cc8fee0f9bab7388574179fef
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.13

Release history Release notifications | RSS feed

This release

2.10.0 This release

2 release files

2.9.2

2 release files

2.9.1

2 release files

2.8.1

2 release files

2.8.0

2 release files

2.7.1

2 release files

2.4.3

2 release files

2.4.2

2 release files

2.4.1

2 release files

2.4.0

2 release files

2.3.0

2 release files

2.2.2

2 release files

2.2.1

2 release files

2.2.0

2 release files

2.1.4

2 release files

2.1.3

2 release files

2.1.2

2 release files

2.1.1

2 release files

2.1.0

2 release files

2.0.2

2 release files

2.0.1

2 release files

2.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page