python-job-scraper
Scrape job listings from multiple job sites with one function call. Results land in a single, normalized pandas.DataFrame.
Supported sites:
- Indeed
- Glassdoor
- Naukri
- Foundit
- Shine
- Internshala
- Upwork
- Apna
from jobscraper import scrape_jobs
jobs = scrape_jobs(
site_name=["indeed", "glassdoor", "linkedin"],
search_term="software engineer",
location="Bangalore",
results_wanted=20,
)
No API keys. No accounts. Chrome 120 TLS fingerprinting keeps requests looking like a real browser.
Installation
Requirements: Python 3.13+
With pip
pip install python-job-scraper
With uv
uv pip install python-job-scraper
From source
git clone https://github.com/seeedstack/job-scraper.git
cd job-scraper
pip install .
Usage
Single site
jobs = scrape_jobs(
site_name="indeed",
search_term="data scientist",
location="Mumbai",
results_wanted=15,
hours_old=48, # only jobs posted in the last 48 hours
job_type="fulltime",
)
print(jobs[["title", "company", "location", "date_posted", "min_amount"]].head())
Multiple sites in parallel
jobs = scrape_jobs(
site_name=["indeed", "glassdoor", "linkedin"],
search_term="product manager",
location="Delhi",
results_wanted=10, # 10 per site → up to 30 total
description_format="markdown",
)
LinkedIn with authentication (richer data)
Without a cookie, LinkedIn returns public job cards — title, company, location, date.
With your li_at cookie, the Voyager API unlocks salary ranges, full descriptions, and direct apply URLs.
LI_AT=your_cookie python examples/test_linkedin.py
jobs = scrape_jobs(
site_name="linkedin",
search_term="machine learning engineer",
location="Hyderabad",
cookies={"li_at": "your_li_at_cookie_value"},
is_remote=True,
)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
site_name |
str | list[str] |
required | "indeed", "glassdoor", "linkedin" |
search_term |
str |
required | Job title or keyword |
location |
str |
None |
City or region |
results_wanted |
int |
20 |
Max results per site |
hours_old |
int |
None |
Exclude jobs older than N hours |
job_type |
str |
None |
"fulltime" "parttime" "contract" "internship" |
is_remote |
bool |
False |
Remote jobs only (LinkedIn) |
distance |
int |
50 |
Search radius in km |
country_indeed |
str |
"india" |
Country for Indeed |
description_format |
str |
"markdown" |
"markdown" or "html" |
enforce_annual_salary |
bool |
False |
Normalize all pay to annual |
offset |
int |
0 |
Skip first N results (for pagination) |
cookies |
dict |
None |
Pass {"li_at": "..."} for LinkedIn Voyager |
proxies |
str | list |
None |
Proxy URL(s) |
verbose |
int |
0 |
0=errors 1=warnings 2=info |
Output columns
| Column | Description |
|---|---|
site |
Source platform |
title |
Job title |
company |
Company name |
location |
City / state / country |
date_posted |
Posting date |
job_type |
Employment type |
is_remote |
Remote flag |
min_amount / max_amount |
Salary range |
interval |
Pay period: hourly monthly yearly |
currency |
Currency code |
description |
Full job description |
job_url |
Link to the listing |
job_url_direct |
Direct apply URL (when available) |
company_url |
Company profile URL |
emails |
Contact emails found in description |
All-NA columns are dropped automatically. Use enforce_annual_salary=True to normalize hourly/monthly/daily rates to annual before comparing across sites.
Running tests
# Unit tests only
pytest tests/
# Include live integration tests (hits real sites)
pytest tests/ -m integration
License
MIT © 2026 saran
This library is intended for personal and research use. Scraping job sites may conflict with their Terms of Service — use responsibly and at your own risk. No warranty is provided for the accuracy or availability of scraped data.
Metadata
Release files for python-job-scraper 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| python_job_scraper-0.3.0.tar.gz | 40.3 kB | Without provenance | Details for python_job_scraper-0.3.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| python_job_scraper-0.3.0-py3-none-any.whl | Python 3 | none | any | Details for python_job_scraper-0.3.0-py3-none-any.whl |
Total release size: 76.7 kB
Release files / python_job_scraper-0.3.0.tar.gz
| Download URL | python_job_scraper-0.3.0.tar.gz |
|---|---|
| Size | 40.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
388f980408d4c242989c3f3cd2e5d7e1c88edaf428e7dc1c06a57a7022552ae5
|
|
BLAKE2b-256 checksum How to use checksums |
c4a31f243c144c5f85a5afde7507573e37e58d848950952f5328b86c0aef5398
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.5
|
Release files / python_job_scraper-0.3.0-py3-none-any.whl
| Download URL | python_job_scraper-0.3.0-py3-none-any.whl |
|---|---|
| Size | 36.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9538d57fd852928373655e03c5bf3a5b21dafb98a342d684ef4cbda28f0019e1
|
|
BLAKE2b-256 checksum How to use checksums |
0773838109f9555a6a5ec5c352457df3848026d68bdc42fd08b3660419aa5bf4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.5
|
Security for python-job-scraper 0.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.