# Indeed Jobs Scraper (Python Version) (`seashell_knighthood/indeed-jobs-scraper-python`) Actor

Scrapes job listings from Indeed using SeleniumBase Undetected ChromeDriver, outputting title, company, location, salary, date, job type, link, and JD snippet.

- **URL**: https://apify.com/seashell\_knighthood/indeed-jobs-scraper-python.md
- **Developed by:** [Mahir Sutar](https://apify.com/seashell_knighthood) (community)
- **Categories:** Automation, Jobs
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-usage

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Indeed Search Scraper (Playwright, stealth, no proxy)

Scrapes job title / company / location / salary / link from Indeed search
result pages, using a headless Chromium browser with stealth patches to
reduce the chance of triggering a bot check.

### Important — read before running

- No proxy or paid CAPTCHA solver is wired up in this version (per your
  choice). That means: if Indeed shows you a CAPTCHA/verification page,
  the scraper will detect it, log a warning, and stop that search rather
  than push through it. You'll need to slow down further, wait a while,
  switch networks, or add a proxy later (there's a `PROXY` slot ready in
  `config.py` for when you do).
- Keep request volume low and delays realistic. Aggressive scraping is
  the #1 reason IPs get flagged. The defaults in `config.py` are
  intentionally conservative — don't crank them down to zero.
- Indeed's HTML structure changes periodically. If you suddenly get zero
  results, open a real search page in your browser, inspect the job
  cards, and update the selectors in `scraper.py` (`CARD_SELECTORS` and
  the fields pulled from each card).
- This is for personal/research use. Scraping Indeed is against their
  Terms of Service — that's a business/legal decision for you to weigh,
  not something this tool resolves.

### Setup

```bash
python -m venv venv
source venv/bin/activate        # Windows: venv\Scripts\activate

pip install -r requirements.txt
playwright install chromium
```

### Configure

Edit `config.py`:

- `KEYWORDS` / `LOCATIONS` — what to search for
- `MAX_PAGES_PER_SEARCH` — how many result pages to pull per search
- `HEADLESS = False` — while debugging, so you can watch the browser and see
  what Indeed is actually serving you
- `PROXY` — fill in later if you get a proxy (format is in the comment)

### Run

```bash
python main.py
```

Results append to `data/indeed_jobs.csv`.

### Next steps you might want later

- Add a proxy (`PROXY` in `config.py`) once request volume goes up —
  this matters more than any stealth trick for avoiding blocks.
- Add full job-description scraping by visiting each `job_link` (a second
  pass, same stealth-context pattern, with its own delays).
- Swap CSV for SQLite if the dataset grows and you want to query/dedupe it.
  \#� �I�n�d�e�e�d�\_�s�c�r�a�p�e�r�  �
  �

# Actor input Schema

## `countryName` (type: `string`):

Which Indeed site to search (e.g. India -> in.indeed.com). This is the country, not the city. Supported: usa, india, uk, canada, germany, france, australia.

## `includeKeyword` (type: `string`):

Comma-separated keywords (e.g., Python Developer, Data Scientist). Each is searched separately.

## `locationName` (type: `string`):

City or region (e.g. 'Bangalore'). Use 'Remote' for remote jobs. Leave empty to search the whole country.

## `companyName` (type: `string`):

Optional. Filter to a specific company (applied via Indeed's 'company:(...)' search operator).

## `radius` (type: `string`):

Distance from the location. Ignored for 'Remote'.

## `jobType` (type: `string`):

Filter by employment type.

## `experienceLevel` (type: `string`):

Filter by required experience level.

## `datePosted` (type: `string`):

How recently the job was posted. Indeed supports up to 14 days.

## `sortBy` (type: `string`):

Order results by relevance (Indeed default) or newest first.

## `pagesToFetch` (type: `integer`):

Number of result pages to scrape (~10-15 jobs per page).

## `strictTitleMatch` (type: `boolean`):

If ON, keep only jobs whose title contains your keyword. If OFF (default), return everything Indeed considers relevant.

## Actor input object example

```json
{
  "countryName": "usa",
  "includeKeyword": "Python Developer",
  "companyName": "",
  "datePosted": "week",
  "sortBy": "relevance",
  "pagesToFetch": 1,
  "strictTitleMatch": false
}
```

# Actor output Schema

## `jobs` (type: `string`):

The scraped Indeed job listings, stored as items in the default dataset.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("seashell_knighthood/indeed-jobs-scraper-python").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("seashell_knighthood/indeed-jobs-scraper-python").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call seashell_knighthood/indeed-jobs-scraper-python --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,seashell_knighthood/indeed-jobs-scraper-python"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/gPAhgTU2JLRjWhCsA/builds/Lf5kBW8fPiNiHs0h1/openapi.json
