# Computrabajo Jobs Scraper (`stilled_stalagmite/computrabajo-jobs-scraper`) Actor

Scrape job listings from Computrabajo Mexico: titles, companies, locations, salaries, and posting dates.

- **URL**: https://apify.com/stilled_stalagmite/computrabajo-jobs-scraper.md
- **Developed by:** [Danilo Frias](https://apify.com/stilled_stalagmite) (community)
- **Categories:** Jobs
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 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.

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

## Computrabajo Jobs Scraper

Scrapes **public job listings from Computrabajo Mexico** (`mx.computrabajo.com`)
without any login. Each run returns structured job records: title, company,
location, salary text, canonical job URL, relative posted date, and a
description snippet field.

Who would use it: labor-market researchers, recruiters doing competitive
benchmarking, job aggregators, and analysts tracking salary ranges or hiring
volume by city/keyword in Mexico. The output is a clean, typed dataset pushed
to the Apify dataset via `Actor.push_data`.

### Inputs

| Field | Type | Default | Description |
|---|---|---|---|
| `search_query` | string | `""` | Job keyword, e.g. `"contador"`, `"vendedor"`. When set, listing URLs are built as `/trabajo-de-<query>[-en-<location>]`, mirroring the site's own search box. Accents and casing are normalized (`"Atención a clientes"` becomes `atencion-a-clientes`). |
| `location` | string | `"Mexico"` | Place to search in, e.g. `"Ciudad de Mexico"`, `"Guadalajara"`. With no search query this builds `/empleos-en-<location>`. The generic value `"Mexico"` falls back to the default `start_urls`. |
| `start_urls` | array of strings | 3 verified city pages (Ciudad de Mexico, Guadalajara, Monterrey) | Explicit Computrabajo listing pages to scrape. When empty, URLs are built from `search_query`/`location` as described above. |
| `max_items` | integer | `50` | Maximum number of **unique** job listings to return (1-2000). The actor paginates each start URL (`?p=2`, `?p=3`, ...) until this many is reached. |

### Sample output record

```json
{
  "title": "Auxiliar contable",
  "company": "YUBZAVA SERVICIOS INTEGRALES",
  "location": "Cuauhtémoc, Ciudad de México DF",
  "salary_text": "$ 12,000.00 (Mensual)",
  "job_url": "https://mx.computrabajo.com/ofertas-de-trabajo/oferta-de-trabajo-de-auxiliar-contable-presencial-en-cuauhtemoc-800D807A4C273BF561373E686DCF3405",
  "posted_date": "Hace 1 hora",
  "description_snippet": null
}
```

Field notes:

- `salary_text` is `null` when the listing shows no salary (common).
- `posted_date` is the site's relative label as shown (e.g. `"Hace 1 hora"`, `"Hace 3 días"`), not normalized to a timestamp.
- `description_snippet` is currently `null`: listing cards carry no description text, and detail pages are not fetched. Listings that hide the employer show `"Importante empresa del sector"` as `company`.

### Coverage and limits

- **Pagination:** ~20 cards per page. The actor follows the site's own
  "Siguiente" link (`span.buildLink[data-path]`), falling back to `?p=N`.
  Deduplication is by `job_url`, so repeated/sponsored cards don't inflate counts.
- **Rate limiting:** ~1 request/second between page fetches, with a normal
  desktop browser User-Agent and browser-like headers. No concurrency.
- **Blocks:** if a page redirects to a login wall, serves a CAPTCHA, or returns
  401/403/429, the actor logs the URL, status code, and redirect target and
  moves on to the next start URL. It never attempts to solve CAPTCHAs or log in.
- **Scope:** Mexico site (`mx.computrabajo.com`) listing pages only. The
  `/ofertas-de-trabajo/` bare path redirects to the homepage, and
  `/empleos-en-mexico` is a geolocation-gated SEO page with no cards, so neither
  is used as a default.

### Data rules

- **Public pages only.** Logged-out scraping of public search-result pages. No
  login flows, no session cookies, no CAPTCHA solving, no proxy services.
- **No personal data.** Job listings show company names (businesses, fine), but
  the scraper deliberately never parses recruiter names, emails, or phone
  numbers, and it never opens job-detail or application pages where personal
  contacts could appear.

### Local run

```bash
## write input, then run from this directory
mkdir -p storage/key_value_stores/default
cat > storage/key_value_stores/default/INPUT.json <<'EOF'
{"search_query": "", "location": "Mexico", "start_urls": [], "max_items": 50}
EOF
python main.py
```

Results land in `storage/datasets/default/` (one JSON file per record).

# Actor input Schema

## `location` (type: `string`):

Place to search in (e.g. 'Ciudad de Mexico', 'Guadalajara'). With no search query this builds /empleos-en-<location>. The generic value 'Mexico' falls back to the default start URLs.

## `max_items` (type: `integer`):

Maximum number of unique job listings to return. The actor paginates each start URL (?p=2, ?p=3, ...) until this many is reached.

## `search_query` (type: `string`):

Job keyword to search for (e.g. 'contador', 'vendedor'). When set, listing URLs are built as /trabajo-de-<query>\[-en-<location>], mirroring the site's own search box.

## `start_urls` (type: `array`):

Explicit Computrabajo Mexico listing pages to scrape. When empty, URLs are built from search_query/location (or the defaults below).

## Actor input object example

```json
{
  "location": "Mexico",
  "max_items": 50,
  "search_query": "",
  "start_urls": [
    {
      "url": "https://mx.computrabajo.com/empleos-en-ciudad-de-mexico"
    },
    {
      "url": "https://mx.computrabajo.com/empleos-en-guadalajara"
    },
    {
      "url": "https://mx.computrabajo.com/empleos-en-monterrey"
    }
  ]
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

# 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("stilled_stalagmite/computrabajo-jobs-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 = {}

# Run the Actor and wait for it to finish
run = client.actor("stilled_stalagmite/computrabajo-jobs-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 '{}' |
apify call stilled_stalagmite/computrabajo-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,stilled_stalagmite/computrabajo-jobs-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/L4U42rqHdsorJUSQi/builds/GFnwdaGg0cfpG4hBr/openapi.json
