Skip to main content

JobSpy

PyPI version Python versions Downloads per month CI License: MIT Discord

JobSpy is a job scraping library that aggregates jobs from popular job boards with one tool:

  • Scrapes job postings from LinkedIn, Indeed, Glassdoor, ZipRecruiter, Bayt, Naukri, BDJobs & HelloWork concurrently
  • Aggregates the job postings in a dataframe
  • Proxy support to bypass blocking

JobSpy demo

Installation

pip install -U python-jobspy

Python version >= 3.10 required

Usage

import csv
from jobspy import scrape_jobs

jobs = scrape_jobs(
    site_name=["indeed", "linkedin", "zip_recruiter", "glassdoor"], # "bayt", "naukri", "bdjobs", "hellowork"
    search_term="software engineer",
    location="San Francisco, CA",
    results_wanted=20,
    hours_old=72,
    country_indeed='USA',
    
    # fetch_description=True # for boards whose search results don't include the description (slower)
    # proxies=["208.195.175.46:65095", "208.195.175.45:65095", "localhost"],
)
print(f"Found {len(jobs)} jobs")
print(jobs.head())
jobs.to_csv("jobs.csv", quoting=csv.QUOTE_NONNUMERIC, escapechar="\\", index=False) # to_excel

Output

SITE           TITLE                             COMPANY           CITY          STATE  JOB_TYPE  INTERVAL  MIN_AMOUNT  MAX_AMOUNT  JOB_URL                                            DESCRIPTION
indeed         Software Engineer                 AMERICAN SYSTEMS  Arlington     VA     None      yearly    200000      150000      https://www.indeed.com/viewjob?jk=5e409e577046...  THIS POSITION COMES WITH A 10K SIGNING BONUS!...
indeed         Senior Software Engineer          TherapyNotes.com  Philadelphia  PA     fulltime  yearly    135000      110000      https://www.indeed.com/viewjob?jk=da39574a40cb...  About Us TherapyNotes is the national leader i...
linkedin       Software Engineer - Early Career  Lockheed Martin   Sunnyvale     CA     fulltime  yearly    None        None        https://www.linkedin.com/jobs/view/3693012711      Description:By bringing together people that u...
linkedin       Full-Stack Software Engineer      Rain              New York      NY     fulltime  yearly    None        None        https://www.linkedin.com/jobs/view/3696158877      Rain’s mission is to create the fastest and ea...
zip_recruiter Software Engineer - New Grad       ZipRecruiter      Santa Monica  CA     fulltime  yearly    130000      150000      https://www.ziprecruiter.com/jobs/ziprecruiter...  We offer a hybrid work environment. Most US-ba...
zip_recruiter Software Developer                 TEKsystems        Phoenix       AZ     fulltime  hourly    65          75          https://www.ziprecruiter.com/jobs/teksystems-0...  Top Skills' Details• 6 years of Java developme...

Parameters for scrape_jobs()

Optional
├── site_name (list|str): 
|    linkedin, zip_recruiter, indeed, glassdoor, google, bayt, bdjobs, naukri, hellowork
|    (default is all)
│
├── search_term (str)
|
├── google_search_term (str)
|     search term for google jobs. This is the only param for filtering google jobs.
│
├── location (str)
│
├── distance (int): 
|    in miles, default 50
│
├── job_type (str): 
|    fulltime, parttime, internship, contract
│
├── proxies (list): 
|    in format ['user:pass@host:port', 'localhost']
|    each job board scraper will round robin through the proxies
|    socks proxies on LinkedIn, Indeed and BDJobs need pip install "requests[socks]"
|
├── is_remote (bool)
│
├── results_wanted (int): 
|    number of job results to retrieve for each site specified in 'site_name'
│
├── easy_apply (bool): 
|    filters for jobs that are hosted on the job board site
|
├── user_agent (str): 
|    override the default user agent which may be outdated
│
├── description_format (str): 
|    markdown, html (Format type of the job descriptions. Default is markdown.)
│
├── offset (int): 
|    starts the search from an offset (e.g. 25 will start the search from the 25th result)
│
├── hours_old (int): 
|    filters jobs by the number of hours since the job was posted 
|    (Glassdoor filters by whole days, so it rounds up to the next day.)
│
├── verbose (int) {0, 1, 2}: 
|    Controls the verbosity of the runtime printouts 
|    (0 prints only errors, 1 is errors+warnings, 2 is all logs. Default is 1.)

├── fetch_description (bool): 
|    for boards whose search results don't include the job description: fetches each job's
|    page for the description and other details (e.g. job type). Without it these are empty
|    for those boards. Adds one request per job, so use proxies for larger searches
│
├── linkedin_fetch_description (bool): 
|    deprecated, use fetch_description (still works; removed in 2.0)
│
├── linkedin_company_ids (list[int]): 
|    searches for linkedin jobs with specific company ids
|
├── country_indeed (str): 
|    filters the country on Indeed & Glassdoor (see below for correct spelling)
|
├── enforce_annual_salary (bool): 
|    converts wages to annual salary
|
├── ca_cert (str)
|    path to CA Certificate file for proxies

Supported Countries for Job Searching

LinkedIn

LinkedIn searches globally & uses only the location parameter.

ZipRecruiter

ZipRecruiter searches for jobs in US/Canada & uses only the location parameter.

Indeed / Glassdoor

Indeed & Glassdoor supports most countries, but the country_indeed parameter is required. Additionally, use the location parameter to narrow down the location, e.g. city & state if necessary.

You can specify the following countries when searching on Indeed (use the exact name, * indicates support for 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*

Bayt

Bayt searches all countries unless location names one it covers, e.g. "Dubai, UAE" or "Saudi Arabia".

BDJobs

BDJobs searches Bangladesh. location takes a division or district, e.g. "Dhaka" or "Chattogram Division".

Naukri

Naukri searches India. location takes a city, e.g. "Pune".

HelloWork

HelloWork searches France. location takes a French city, postcode or region, e.g. "Lyon". Most jobs are posted in French, so French search terms find more.

Notes

  • Indeed is the best scraper currently with no rate limiting.
  • Indeed's date_posted is the day a job was added to Indeed, the same date hours_old filters on.
  • Most job board endpoints are capped at around 1000 jobs on a given search.
  • LinkedIn rate limits bursts of requests with a 429, which clears within about a minute. Use proxies for larger searches.
  • Glassdoor rate limits above about 2 requests a second.

Frequently Asked Questions

Q: Why is Indeed giving unrelated roles?
A: Indeed searches the description too.

  • use - to remove words
  • "" for exact match

Example of a good Indeed query

search_term='"engineering intern" software summer (java OR python OR c++) 2025 -tax -marketing'

This searches the description/title and must include software, summer, 2025, one of the languages, engineering intern exactly, no tax, no marketing.


Q: No results when using "google"?
A: Google Jobs is currently unavailable.


Q: Received a response code 429?
A: This indicates that you have been blocked by the job board site for sending too many requests. All of the job board sites are aggressive with blocking. We recommend:

  • Wait some time between scrapes (site-dependent).
  • Try using the proxies param to change your IP address.

JobPost Schema

JobPost
├── id
├── site
├── job_url
├── job_url_direct
├── title
├── company
├── location
├── date_posted
├── job_type: fulltime, parttime, internship, contract, temporary, ...
├── salary_source: direct_data, description (parsed from posting)
├── interval: yearly, monthly, weekly, daily, hourly
├── min_amount
├── max_amount
├── currency
├── is_remote
├── job_level
├── job_function
├── listing_type
├── emails
├── description
├── company_industry
├── company_url
├── company_logo
├── company_url_direct
├── company_addresses
├── company_num_employees
├── company_revenue
├── company_description
├── skills
├── experience_range
├── company_rating
├── company_reviews_count
├── vacancy_count
└── work_from_home_type

A column is empty when the job board doesn't provide it.

Metadata

Release files for python-jobspy 1.3.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 python-jobspy 1.3.0
File Size Uploaded
python_jobspy-1.3.0.tar.gz 45.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for python-jobspy 1.3.0
File Interpreter ABI Platform
python_jobspy-1.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 102.3 kB

Release files / python_jobspy-1.3.0.tar.gz

Download URL python_jobspy-1.3.0.tar.gz
Size 45.6 kB
Tags Source
SHA-256 checksum
How to use checksums
b840c434262e057ab8ae89895b6c2b271d86de9d9505d9da957772054c61736a
BLAKE2b-256 checksum
How to use checksums
85db827e27167d31a99f9212044ace18d9bdea3aa3b6f9913aa5f04b3c6cc538
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / python_jobspy-1.3.0-py3-none-any.whl

Download URL python_jobspy-1.3.0-py3-none-any.whl
Size 56.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
74e19fa6b1313668541a7a4bc0d51d714534740a70d6f11533ef921715d15017
BLAKE2b-256 checksum
How to use checksums
0f8725fe81256d159959649cacee84f28d13019dd6c4b63d5ba67330ab3ff223
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

This release

1.3.0 This release

2 release files

1.2.0

2 release files

1.1.82

2 release files

1.1.80

2 release files

1.1.79

2 release files

1.1.77

2 release files

1.1.75

2 release files

1.1.74

2 release files

1.1.73

2 release files

1.1.72

2 release files

1.1.71

2 release files

1.1.70

2 release files

1.1.67

2 release files

1.1.66

2 release files

1.1.65

2 release files

1.1.64

2 release files

1.1.61

2 release files

1.1.60

2 release files

1.1.59

2 release files

1.1.58

2 release files

1.1.55

2 release files

1.1.54

2 release files

1.1.53

2 release files

1.1.52

2 release files

1.1.51

2 release files

1.1.50

2 release files

1.1.49

2 release files

1.1.45

2 release files

1.1.44

2 release files

1.1.36

2 release files

1.1.35

2 release files

1.1.34

2 release files

1.1.33

2 release files

1.1.32

2 release files

1.1.29

2 release files

1.1.28

2 release files

1.1.25

2 release files

1.1.24

2 release files

1.1.23

2 release files

1.1.22

2 release files

1.1.21

2 release files

1.1.17

2 release files

1.1.16

2 release files

1.1.15

2 release files

1.1.14

2 release files

1.1.13

2 release files

1.1.11

2 release files

1.1.10

2 release files

1.1.9

2 release files

1.1.8

2 release files

1.1.7

2 release files

1.1.5

2 release files

1.1.4

2 release files

1.1.3

2 release files

1.1.2

2 release files

1.1.1

2 release files

1.1.0

2 release files

1.0.3

2 release files

1.0.1

2 release files

1.0.0

2 release files

0.1.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