# InfoJobs Scraper - Spain Jobs, Full Descriptions & Companies (`haketa/infojobs-scraper`) Actor

Scrape InfoJobs, Spain's #1 job board. Extract job offers by keyword, city or category: title, company, location, contract type, working day, remote/hybrid and the full job description. Export to JSON, CSV or Excel for recruiting, aggregation and lead generation.

- **URL**: https://apify.com/haketa/infojobs-scraper.md
- **Developed by:** [Haketa](https://apify.com/haketa) (community)
- **Categories:** Jobs, Lead generation
- **Features:** Limited permissions
- **Stats:** 9 total users, 3 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.75 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## 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

## 🇪🇸 InfoJobs Scraper — Spain Job Offers, Full Descriptions & Hiring Companies

**Extract job offers from [InfoJobs](https://www.infojobs.net) — Spain's largest employment marketplace — into clean, structured data.** This **InfoJobs scraper** lets you **scrape InfoJobs** by keyword, city, province or filtered search URL and export hundreds to **1,000+ vacancies** with **job title, hiring company name, company profile URL, company logo, city, province, contract type, working day, remote/hybrid arrangement (`teleworking`), executive flag, publish timestamp and the complete full-text job description** — no login, no coding.

Export every job offer to **JSON, CSV, Excel, or API** in one click for **recruitment sourcing**, **B2B lead generation**, and **Spanish labor-market intelligence**.

[![Apify Actor](https://img.shields.io/badge/Apify-Actor-00b04f?style=flat-square\&logo=apify)](https://apify.com/haketa/infojobs-scraper)
[![Market](https://img.shields.io/badge/Market-Spain%20🇪🇸-c60b1e?style=flat-square)](https://apify.com/haketa/infojobs-scraper)
[![Pagination](https://img.shields.io/badge/Pagination-Auto%201%2C000%2B%20Offers-blue?style=flat-square)](https://apify.com/haketa/infojobs-scraper)
[![Full Description](https://img.shields.io/badge/Job%20Description-Full%20Text%20\(~2%2C000%2B%20chars\)-success?style=flat-square)](https://apify.com/haketa/infojobs-scraper)
[![Export](https://img.shields.io/badge/Export-JSON%20%7C%20CSV%20%7C%20Excel%20%7C%20API-2b7489?style=flat-square)](https://apify.com/haketa/infojobs-scraper)
[![No Auth](https://img.shields.io/badge/Login-None%20Required-success?style=flat-square)](https://apify.com/haketa/infojobs-scraper)

> Built for **recruitment agencies, technical sourcers, B2B sales & lead-generation teams, job-board aggregators, HR compensation analysts and labor-market researchers** operating in Spain and the EU.

***

### ⚡ At a glance

| Feature | Details |
|---|---|
| **Target platform** | [InfoJobs Spain (`infojobs.net`)](https://www.infojobs.net) |
| **Search inputs** | Any job keyword(s) (`developer`, `marketing`, `comercial`, `enfermero`…) and/or any InfoJobs search URL (`startUrls`) |
| **Core data extracted** | Offer ID (`id`), `title`, `company`, `companyUrl`, `companyLogo`, `city`, `province`, `contractType`, `workday`, `teleworking`, `isExecutive`, `publishedAt`, and **full-text `description`** |
| **Remote / hybrid filter** | Built-in `onlyTeleworking` toggle to keep only `Teletrabajo` / `Solo teletrabajo` and `Híbrido` roles |
| **Pagination & 1,000+ scale** | Automatic 22-offer/page pagination up to 1,000 pages per query + multi-keyword expansion (`maxItems: 0` = unlimited, supports 1,000+ offers) |
| **Deduplication** | 100% deduplicated by unique InfoJobs offer `id` across pages, keywords and search URLs |
| **Execution speed** | Fast HTTP extraction with automatic proxy rotation — collects 100 offers in seconds and 500+ offers in ~1 minute |
| **Export formats** | Bulk export to JSON, CSV, Excel, XML, HTML, RSS, Webhook & Apify REST API |

***

### 🔎 Why scrape InfoJobs?

[InfoJobs (`infojobs.net`)](https://www.infojobs.net) is the #1 employment portal in Spain, hosting hundreds of thousands of active job listings across Madrid, Barcelona, Valencia, Sevilla, Bilbao, Málaga, Zaragoza and every Spanish province. When Spanish enterprises, SMEs and international tech hubs hire in Spain, InfoJobs is where vacancies appear first — making it the premier source of live **Spain job market data** and **hiring-company buying signals**.

Collecting InfoJobs data manually is slow and restrictive: search results are paginated 22 offers per page, filters reset between searches, and naive scrapers get blocked or only capture short card snippets instead of the full job description. This **InfoJobs data extractor** solves all of those challenges automatically: it translates any keyword or `/ofertas-trabajo/` URL, paginates deeply across result pages, extracts the **complete 2,000+ character job description** directly from the search feed without needing slow per-offer detail requests, and deduplicates every offer by its unique `id`.

**Common reasons teams use this InfoJobs scraper:**

- 🎯 **B2B sales & lead generation** — identify Spanish companies actively hiring (`company`, `companyUrl`, `city`, `isExecutive`) as a high-intent trigger for HR tech, SaaS, staffing and B2B services outreach.
- 🧲 **Recruitment & candidate sourcing** — monitor newly published roles (`publishedAt`) across tech, healthcare, sales, engineering and finance before competitors react.
- 📝 **NLP skill, tech-stack & salary mining** — analyze thousands of full-text `description` fields to extract required skills, languages, certifications and embedded salary bands.
- 🗞️ **Job boards & career aggregators** — ingest clean, structured Spanish vacancies with direct `url` and `companyLogo` links into vertical job portals or newsletters.
- 📊 **Regional & remote-work analytics** — track `teleworking` (`Presencial`, `Híbrido`, `Solo teletrabajo`), `contractType` (`Contrato indefinido`, `temporal`, `autónomo`) and `workday` trends across Spanish cities.

***

### ✨ What this InfoJobs scraper does

- ✅ **Search by keyword or full InfoJobs URL** — enter keywords (`developer`, `data analyst`, `marketing`, `administrativo`) or paste any filtered URL from `infojobs.net/ofertas-trabajo/...` into `startUrls`.
- ✅ **Complete job description included on every row** — unlike basic scrapers that return a 150-character snippet, every record includes the **entire job description text** (typically 1,500–4,000 characters) without extra detail-page requests.
- ✅ **Unlocked 1,000+ offer pagination** — automatically walks through result pages (`22` offers per page) and expands across multiple keywords when `maxItems` is set to `1,000+` or `0` (unlimited).
- ✅ **Zero-config empty run support** — running with empty input (`{}`) automatically collects a diverse 100-offer sample across Spain's top job categories so runs never fail on empty parameters.
- ✅ **One-click remote/hybrid filter (`onlyTeleworking`)** — filter your dataset on the fly to keep only remote (`Teletrabajo`) and hybrid (`Híbrido`) positions.
- ✅ **Rich hiring-company metadata** — captures `company` name, direct InfoJobs `companyUrl` profile link, and `companyLogo` image URL.
- ✅ **Smart proxy rotation & resilience** — runs on Apify Proxy out of the box with automatic session rotation and residential fallback if rate-limited.
- ✅ **Streamed dataset + KVS `OUTPUT` mirror** — pushes batches live to the Apify Dataset as each page completes and writes the full array to `OUTPUT` in the Key-Value Store.

***

### 🎯 Use cases

| Persona | How they use this Actor |
|---|---|
| **🏢 Staffing & Recruitment Agencies** | Track daily job postings in Madrid, Barcelona and Valencia by keyword (`ingeniero`, `enfermero`, `comercial`) to pitch contingency staffing services to hiring managers. |
| **🚀 B2B Growth & Outbound Teams** | Build targeted account lists of companies expanding their teams (`company`, `companyUrl`, `city`) and personalize outreach based on the exact roles they are hiring for. |
| **🌐 Job Aggregators & Niche Portals** | Populate remote-work or tech-focused job boards in Spain using `onlyTeleworking: true` and multiple tech keywords (`developer`, `devops`, `data`, `cybersecurity`). |
| **📈 Labor Economists & HR Analysts** | Measure the share of permanent contracts (`Contrato indefinido`), full-time roles (`Jornada completa`), executive positions (`isExecutive`) and hybrid work across industries. |
| **🔍 Competitive Intelligence Teams** | Monitor competitor hiring velocity and job descriptions to spot new product lines, tech-stack migrations or regional office openings across Spain. |

***

### 📥 Input configuration

All input fields are optional. With the default prefill (`keywords: ["developer"]`, `maxItems: 100`), the Actor finishes in under a minute; with empty input (`{}`), it collects 100 offers across top Spanish job keywords.

| Field | Type | Default | Description |
|---|---|---|---|
| `startUrls` | array | Prefill `developer` URL | InfoJobs search URLs (`https://www.infojobs.net/ofertas-trabajo/developer` or `.../list.xhtml?...`). Supports all site filters. |
| `keywords` | array | Prefill `["developer"]` | One or more job keywords to search (e.g. `developer`, `marketing`, `comercial`, `enfermero`). Combined and deduplicated with `startUrls`. |
| `onlyTeleworking` | boolean | `false` | Keep only offers marked as remote (`Teletrabajo` / `Solo teletrabajo`) or hybrid (`Híbrido`). |
| `maxItems` | integer | `200` (prefill `100`) | Maximum unique job offers to collect across all URLs and keywords. Set `0` for unlimited, or `1000+` for deep market sweeps. |
| `proxyConfiguration` | object | `{ "useApifyProxy": true }` | Apify Proxy configuration. Enabled by default with automatic IP rotation. |

#### Input example — multi-keyword 1,000+ offer sweep

```json
{
  "keywords": [
    "developer",
    "data engineer",
    "devops",
    "product manager",
    "cybersecurity",
    "marketing digital"
  ],
  "onlyTeleworking": false,
  "maxItems": 1000,
  "proxyConfiguration": { "useApifyProxy": true }
}
```

#### Input example — remote & hybrid jobs only via search URL

```json
{
  "startUrls": [
    { "url": "https://www.infojobs.net/ofertas-trabajo/marketing" },
    { "url": "https://www.infojobs.net/ofertas-trabajo/diseno" }
  ],
  "onlyTeleworking": true,
  "maxItems": 300,
  "proxyConfiguration": { "useApifyProxy": true }
}
```

***

### 📤 Output & field reference

Each job offer is saved as a clean, flat JSON object. Below is a real record from an InfoJobs run:

```json
{
  "id": "9a91be1d18418db6cf6393f7e87c4e",
  "url": "https://www.infojobs.net/las-palmas-de-gran-canaria/tecnico-marketing-comunicacion-enfoque-comercial-./of-i9a91be1d18418db6cf6393f7e87c4e",
  "title": "Técnico de Marketing & Comunicación (Enfoque Comercial).",
  "company": "Globaenergy",
  "companyUrl": "https://www.infojobs.net/globaenergy/em-i98515756505252711081111016194627800302",
  "companyLogo": "https://multimedia-logos.infojobs.net/image/upload/cf/cf900a37-b3a8-4709-be38-84d4e06ff7da",
  "city": "Las Palmas de Gran Canaria",
  "province": null,
  "contractType": "Contrato indefinido",
  "workday": "Jornada parcial - mañana",
  "teleworking": "Presencial",
  "isExecutive": false,
  "publishedAt": "2026-10-30T14:00:06Z",
  "description": "Buscamos Técnico de Marketing & Comunicación (Enfoque Comercial). En Globa, empresa consolidada del sector energético con más de 12 años de trayectoria...",
  "scrapedAt": "2026-11-10T02:50:12.410Z"
}
```

#### 💼 Job Offer & Role Identity

| Field | Type | Coverage | Description |
|---|---|---|---|
| `id` | string | 🟢 High (100%) | Unique InfoJobs offer code (e.g. `9a91be1d18418db6cf6393f7e87c4e`), used for automatic deduplication. |
| `url` | string | 🟢 High (100%) | Direct `https://www.infojobs.net/...` link to the job posting (tracking query parameters stripped). |
| `title` | string | 🟢 High (100%) | Job offer headline / role title. |
| `description` | string | 🟢 High (100%) | **Complete full-text job description** (~2,000+ characters on average), including duties, requirements and benefits. |
| `isExecutive` | boolean | 🟢 High (100%) | `true` when the role is classified as executive / senior management, otherwise `false`. |
| `publishedAt` | string | 🟢 High (100%) | ISO 8601 publication / refresh timestamp (`2026-10-30T14:00:06Z`). |
| `scrapedAt` | string | 🟢 High (100%) | ISO 8601 timestamp when the record was extracted. |

#### 🏢 Company, Location & Work Arrangement

| Field | Type | Coverage | Description |
|---|---|---|---|
| `company` | string | 🟢 High (100%) | Name of the hiring company or recruitment agency. |
| `companyUrl` | string | 🟢 High (~99%) | Direct link to the employer's profile page on InfoJobs. |
| `companyLogo` | string | 🟢 High (~75%) | Employer logo URL on `multimedia-logos.infojobs.net` when uploaded by the company. |
| `city` | string | 🟢 High (100%) | Municipality / city where the job is located (`Madrid`, `Barcelona`, `Valencia`…). |
| `province` | string | 🟡 Conditional (~29%) | Province label when explicitly populated in the search state array; otherwise `null` (use `city`). |
| `contractType` | string | 🟢 High (100%) | Spanish contract classification (`Contrato indefinido`, `De duración determinada`, `Autónomo`, `Formativo`, `Otros contratos`). |
| `workday` | string | 🟢 High (100%) | Working schedule (`Jornada completa`, `Jornada parcial - mañana`, `Jornada intensiva`, `Jornada indiferente`). |
| `teleworking` | string | 🟢 High (~93%) | Work mode (`Presencial`, `Híbrido`, `Solo teletrabajo`), when specified by the employer. |

***

### 🔁 Pagination & 1,000+ scaling

InfoJobs returns **22 job offers per page** and exposes the total matching count (`totalElements`). The **InfoJobs scraper** handles deep pagination automatically:

- **Deep multi-page crawling**: For each search URL or keyword, the Actor increments `?page=1, 2, 3, …` up to 1,000 pages per query until `maxItems` is reached or the search results end.
- **Automatic multi-keyword expansion**: When `maxItems` is set to a large target (e.g. `1,000+`) or when the Actor is started with empty input (`{}`), it automatically queues additional high-volume Spanish job keywords (`developer`, `marketing`, `comercial`, `administrativo`, `ingeniero`, `ventas`, `contable`, `logistica`, `mantenimiento`, `recursos humanos`, `data`, `soporte`) if your initial keyword exhausts early.
- **Cross-query deduplication**: Offers are deduplicated in memory by their unique `id` code across all pages, keywords and URLs so you never receive duplicate listings.

***

### ⚙️ How to use

1. Open **InfoJobs Scraper** in the Apify Console and click **Try for free**.
2. Enter one or more **`keywords`** (e.g. `developer`, `marketing`, `comercial`) or paste filtered InfoJobs URLs into **`startUrls`**.
3. Optionally enable **`onlyTeleworking`** to filter for remote/hybrid jobs, and set **`maxItems`** (`100` for a fast test, `500` or `1,000+` for a large dataset, or `0` for unlimited).
4. Click **Start** and export your results to **JSON, CSV, Excel, XML, or API**.

***

### 🔌 API usage

#### Start a run via REST API

```bash
curl -X POST "https://api.apify.com/v2/acts/haketa~infojobs-scraper/runs?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "keywords": ["developer", "data analyst", "devops"],
    "onlyTeleworking": false,
    "maxItems": 300,
    "proxyConfiguration": { "useApifyProxy": true }
  }'
```

#### Call from Node.js (`apify-client`)

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

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('haketa/infojobs-scraper').call({
    keywords: ['marketing', 'comercial'],
    onlyTeleworking: true,
    maxItems: 500,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(`Fetched ${items.length} InfoJobs offers`);
```

***

#### Call from Python (`apify-client`)

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")

run_input = {
    "keywords": ["developer", "data engineer", "cybersecurity", "marketing"],
    "onlyTeleworking": False,
    "maxItems": 500,
    "proxyConfiguration": {"useApifyProxy": True},
}

run = client.actor("haketa/infojobs-scraper").call(run_input=run_input)

for offer in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(f"{offer['title']} @ {offer['company']} ({offer['city']}) | {offer['contractType']} | {offer['teleworking']}")
```

#### Run synchronously and fetch JSON in one HTTP call

```bash
curl -X POST "https://api.apify.com/v2/acts/haketa~infojobs-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "keywords": ["developer"],
    "onlyTeleworking": true,
    "maxItems": 100
  }'
```

***

### 🔄 Integrations & recruitment automation workflows

Connect **InfoJobs Scraper** directly into your Spanish recruiting, B2B outbound or labor-analytics stack:

| Integration | Workflow example |
|---|---|
| **🏢 HubSpot, Salesforce & Pipedrive** | Automatically create or enrich B2B prospect accounts whenever a Spanish company posts a new vacancy (`company`, `companyUrl`, `city`, `title`, `isExecutive`). |
| **📊 Google Sheets & Airtable** | Schedule daily runs for your target niches (`enfermero`, `ingeniero`, `comercial`, `developer`) and append deduplicated offers (`id`) to a live sourcing tracker. |
| **⚡ Make, Zapier & n8n** | Filter incoming offers by `teleworking` (`Solo teletrabajo` / `Híbrido`) or keywords in `description`, then route matching roles to Slack, Telegram or email digests. |
| **🗄️ Snowflake, BigQuery & PostgreSQL** | Build a longitudinal warehouse of Spanish job postings to analyze hiring velocity by municipality (`city`), contract stability (`contractType`) and skill demand. |
| **🤖 AI Recruiting & NLP Pipelines** | Pass the full-text `description` (~2,000+ characters per offer) to an LLM to extract structured salary bands, required tech stacks, years of experience and language requirements. |

***

### ⚠️ Limitations & data notes

- **Salary disclosure in Spain**: Most employers on InfoJobs do not populate a dedicated structured salary badge on search cards, or they embed compensation ranges inside the body text. The Actor captures the **complete full-text `description`** on every offer so you can parse disclosed salary figures (`€30.000 - €45.000`) directly from the text.
- **Province vs. City**: InfoJobs' search feed consistently populates `city` (`100%` coverage across Spanish municipalities), while the `province` state array is only populated on a subset of offers (~29%). Always use `city` as your primary geographic key.
- **Per-query pagination depth**: Each individual keyword or search URL paginates up to 1,000 pages (~22,000 offers). For full nationwide sweeps, pass multiple sector keywords or regional search URLs in a single run.

***

### 💡 Pro tips for Spanish job data

- **Combine multiple related keywords** (e.g. `["python", "java", "react", "devops", "cloud"]`) with `maxItems: 1000` to build a comprehensive, deduplicated sector dataset in a single run.
- **Use InfoJobs' native web filters via `startUrls`**: filter by province, category or experience level on `infojobs.net`, copy the browser URL, and paste it into `startUrls`.
- **Mine `description` for salary ranges and tech stacks**: many Spanish employers include gross annual salary (`€35.000 - €45.000 brutos/año`) inside the body text rather than a separate badge — since `description` contains the full text, a simple regex extracts it cleanly.
- **Schedule daily runs and deduplicate on `id`** to feed real-time Spanish hiring alerts into Slack, HubSpot, Salesforce or Google Sheets.

***

### ❓ FAQ

**How many job offers can I scrape per run?**
From a 100-item sample up to **10,000+ unique job offers** per run. Set `maxItems` to `1000` (or `0` for unlimited) and pass multiple keywords or broad search URLs.

**Do I need an InfoJobs account or login?**
No. The Actor extracts publicly listed job offers without requiring any account or credentials.

**Does it extract the full job description or just a summary snippet?**
It extracts the **complete job description text** (~2,000+ characters on average) directly from the search payload, giving you full detail-page text at search-page speed.

**Do I need to configure special proxies?**
No. Apify Proxy is enabled by default (`{ "useApifyProxy": true }`), and the Actor automatically rotates proxy sessions and escalates to residential IPs if a datacenter IP is ever challenged.

**What happens if I run the Actor with completely empty input (`{}`)?**
Instead of failing or returning 0 items, an empty run automatically searches across a curated list of Spain's highest-volume job categories (`developer`, `marketing`, `comercial`, `administrativo`, `ingeniero`, `ventas`, `contable`, `logistica`…) and returns a ready-to-use **100-offer sample**.

**How can I filter by Spanish city, province, contract type or experience level?**
Open [InfoJobs (`infojobs.net`)](https://www.infojobs.net) in your browser, apply any combination of location, category, contract (`Contrato indefinido`, `temporal`), workday (`Jornada completa`, `parcial`) or experience filters, copy the resulting browser URL (either `/ofertas-trabajo/...` or `/jobsearch/search-results/list.xhtml?...`), and paste it into `startUrls`. The Actor preserves your URL query parameters while paginating through all matching pages.

**How are duplicate job offers handled when searching multiple keywords?**
Every InfoJobs vacancy has a unique alphanumeric offer code (`id`, e.g. `9a91be1d18418db6cf6393f7e87c4e`). The Actor maintains an in-memory deduplication set across all pages, `startUrls` and `keywords`, guaranteeing **0 duplicate records** in your exported dataset.

**Can I fetch the entire output in a single Key-Value Store call?**
Yes. Alongside incremental Dataset pushes, the Actor writes the complete deduplicated array to the `OUTPUT` key in the default Key-Value Store (`.../key-value-stores/DEFAULT/records/OUTPUT`), making it easy to consume from lightweight webhooks and serverless functions.

#### Sample Spanish job search playbooks

| Playbook | Recommended input configuration |
|---|---|
| **💻 Spain Tech & Software Engineering Sweep** | `keywords`: `["developer", "frontend", "backend", "fullstack", "devops", "data engineer", "qa", "ciberseguridad"]`, `maxItems`: `1000` |
| **🏠 100% Remote & Hybrid Roles Across Spain** | `keywords`: `["developer", "marketing", "diseño", "atencion al cliente", "ventas", "data"]`, `onlyTeleworking`: `true`, `maxItems`: `500` |
| **📈 B2B Commercial & Sales Hiring Signals** | `keywords`: `["comercial", "account executive", "business development", "key account manager", "ventas b2b"]`, `maxItems`: `500` |
| **🏥 Healthcare, Engineering & Industrial Roles** | `keywords`: `["enfermero", "medico", "ingeniero industrial", "mantenimiento", "prevencion riesgos", "logistica"]`, `maxItems`: `500` |

#### Spanish contract & teleworking values reference

| Field | Common Spanish values on InfoJobs | English equivalent |
|---|---|---|
| `contractType` | `Contrato indefinido` | Permanent / full-term employment contract |
| `contractType` | `De duración determinada` | Fixed-term / temporary contract |
| `contractType` | `Autónomo` | Freelance / independent contractor |
| `contractType` | `Formativo` | Internship / training contract |
| ` contractType` | `Fijo discontinuo` | Seasonal permanent contract |
| `workday` | `Jornada completa` | Full-time schedule |
| `workday` | `Jornada parcial - mañana` / `tarde` | Part-time schedule (morning / afternoon) |
| `workday` | `Jornada intensiva` | Intensive / continuous shift schedule |
| `workday` | `Jornada indiferente` | Flexible / unspecified schedule |
| `teleworking` | `Presencial` | 100% On-site |
| `teleworking` | `Híbrido` | Hybrid (remote + office) |
| `teleworking` | `Solo teletrabajo` / `Teletrabajo` | 100% Remote work |

#### How to extract salary bands from `description` in Python

Because `description` contains the complete full-text job offer, you can extract disclosed gross annual salaries (`€30.000 - €45.000`) with a single regular expression:

```python
import re

SALARY_RE = re.compile(r"(\d{2}[.,]?\d{3})\s*(?:€|euros?)?\s*(?:-|a|hasta)\s*(\d{2}[.,]?\d{3})\s*(?:€|euros?)", re.I)

def extract_salary_range(description: str):
    match = SALARY_RE.search(description or "")
    if not match:
        return None
    low = int(match.group(1).replace(".", "").replace(",", ""))
    high = int(match.group(2).replace(".", "").replace(",", ""))
    return {"minSalaryEur": low, "maxSalaryEur": high}
```

***

### 🔗 Related scrapers

Building a European or global recruitment intelligence pipeline? Pair **InfoJobs Scraper** with these job-board scrapers by the same developer:

- [StepStone Scraper — Germany & EU Job Listings](https://apify.com/haketa/stepstone-scraper)
- [Xing Jobs Scraper — DACH Job Listings & Salaries](https://apify.com/haketa/xing-jobs-scraper)
- [SEEK Scraper — Australia & NZ Job Listings with Salary](https://apify.com/haketa/seek-scraper)
- [ZipRecruiter Job Listings & Salary Scraper (US, UK, CA)](https://apify.com/haketa/ziprecruiter-scraper)
- [GulfTalent Jobs Scraper — Gulf Jobs, Salaries & Leads](https://apify.com/haketa/gulftalent-jobs-scraper)
- [Workana Jobs Scraper — Freelance Projects, Budgets & Skills](https://apify.com/haketa/workana-scraper)

***

### 📋 Changelog

- **v1.2 (2026-11)** — Unlocked **1,000+ job offer pagination** (up to 1,000 pages per query + automatic multi-keyword expansion), added zero-config empty-run default keyword fallback (`100` offers), added automatic residential proxy fallback on retry, added `scrapedAt` timestamp and Key-Value Store `OUTPUT` mirror, and tuned fast 100-item prefill.
- **v1.1 (2026-11)** — Upgraded HTTP extraction engine with Firefox TLS fingerprinting and embedded `__INITIAL_PROPS__` parsing to clear interstitial challenges on standard proxies; verified 500-offer run with 100% core field coverage and 0 duplicates.
- **v1.0 (2026-10)** — Initial release with keyword and URL search, full job description extraction, and remote/hybrid (`onlyTeleworking`) filtering.

# Changelog

This Actor's version history is a separate document: https://apify.com/haketa/infojobs-scraper/changelog.md

# Actor input Schema

## `startUrls` (type: `array`):

Search on InfoJobs (by keyword, city, category, filters…) and paste the resulting results-page URL here (e.g. https://www.infojobs.net/ofertas-trabajo/developer). The scraper paginates automatically. Leave empty to use the keywords below.

## `keywords` (type: `array`):

One or more job keywords to search (e.g. developer, marketing, enfermero). Used alongside or instead of search URLs.

## `onlyTeleworking` (type: `boolean`):

When enabled, keep only offers marked as remote (Teletrabajo) or hybrid (Híbrido).

## `maxItems` (type: `integer`):

Maximum number of unique job offers to collect across all URLs / keywords. Set 0 for unlimited.

## `proxyConfiguration` (type: `object`):

Proxy settings. Apify Proxy is enabled by default for reliable, uninterrupted results.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.infojobs.net/ofertas-trabajo/developer"
    }
  ],
  "keywords": [
    "developer"
  ],
  "onlyTeleworking": false,
  "maxItems": 100,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `id` (type: `string`):

Unique InfoJobs offer code

## `url` (type: `string`):

Direct link to the job offer

## `title` (type: `string`):

Job title

## `company` (type: `string`):

Hiring company name

## `companyUrl` (type: `string`):

Company profile URL

## `companyLogo` (type: `string`):

Company logo image URL

## `city` (type: `string`):

Job location city

## `province` (type: `string`):

Province or region when present

## `contractType` (type: `string`):

Contract type

## `workday` (type: `string`):

Working day (full/part time)

## `teleworking` (type: `string`):

On-site, hybrid or remote

## `isExecutive` (type: `string`):

Whether the offer is flagged as executive

## `publishedAt` (type: `string`):

Publish date (ISO 8601)

## `description` (type: `string`):

Full job description text

## `scrapedAt` (type: `string`):

ISO scrape timestamp

# 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 = {
    "startUrls": [
        {
            "url": "https://www.infojobs.net/ofertas-trabajo/developer"
        }
    ],
    "keywords": [
        "developer"
    ],
    "maxItems": 100,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("haketa/infojobs-scraper").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 = {
    "startUrls": [{ "url": "https://www.infojobs.net/ofertas-trabajo/developer" }],
    "keywords": ["developer"],
    "maxItems": 100,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("haketa/infojobs-scraper").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 '{
  "startUrls": [
    {
      "url": "https://www.infojobs.net/ofertas-trabajo/developer"
    }
  ],
  "keywords": [
    "developer"
  ],
  "maxItems": 100,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call haketa/infojobs-scraper --silent --output-dataset

```

## MCP server setup

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

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/Crm4d2xna6fdXQhvv/builds/gJRpGkdIURn9UlAVL/openapi.json
