# Saramin Job Scraper | Salary, Contacts & Company Intel (`corvuslab/saramin-scraper`) Actor

Scrape Saramin (saramin.co.kr), South Korea's largest job board. Extract listings with salary, qualifications, benefits, recruiter contacts, and company intelligence. Incremental monitoring and multi-channel notifications built in.

- **URL**: https://apify.com/corvuslab/saramin-scraper.md
- **Developed by:** [Corvuslab](https://apify.com/corvuslab) (community)
- **Categories:** Jobs, Automation, Lead generation
- **Stats:** 1 total users, 0 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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Saramin Job Scraper | Salary, Contacts & Company Intel

### What does Saramin Scraper do?

Extract job listings from [Saramin](https://www.saramin.co.kr/) (saramin.co.kr), South Korea's largest job board — with salary, qualifications, benefits, recruiter contacts, and company intelligence. Output is clean, structured JSON ready for CSV, Excel, API, or AI-agent consumption — no code required.

Give it a search keyword (e.g. `개발자`, `python`, `마케팅`) and, optionally, filters like location, experience level, or employment type, and it returns every matching job as a structured record. For each job you get the title, company, location, experience and education requirements, employment type, salary, deadline, posting date, and category tags.

Turn on **Fetch full details** (the default) to also pull qualifications, preferred qualifications, benefits, the recruiter's name and phone number, company intelligence (CEO, type, industry, headcount), and the full job description in text, HTML, and Markdown — plus emails, phone numbers, URLs, and social profiles extracted from the description text.

> New to Apify? You can sign up for free and use the included monthly platform credit to try this Actor.

### Key features

- 🔍 **Search or URL scraping** — run a keyword search across Saramin, or paste any Saramin search or job-detail URL directly.
- 🧱 **Structured records** — title, company, location, experience, education, employment type, salary, deadline, posted date, category tags, and badge.
- 🔬 **Detail enrichment** — fetch each job's detail page for salary figures, required qualifications, preferred qualifications, benefits, application method, recruiter contact name and phone, and the full job description in text, HTML, or Markdown.
- 🏢 **Company intelligence** — CEO name, company type (KOSPI/KOSDAQ/SME), industry classification, and employee headcount — all from the detail page.
- 🎚️ **Rich filters** — location (17 Korean regions), experience level, education level, employment type, minimum annual salary, remote-work only, exclude keyword, and six sort orders — all applied by Saramin itself.
- 📇 **Contacts & demand signals** — recruiter name, phone number, plus emails, phones, URLs, and social profiles extracted from job descriptions (filter with `requireContact`).
- ♻️ **Incremental monitoring** — schedule it and get only what changed (NEW / UPDATED / EXPIRED); unchanged items are skipped before their page is even fetched.
- 🔔 **Notifications** — Telegram, Slack, Discord or any webhook (n8n / Make / Zapier).
- 🤖 **AI-ready** — compact + drop-empty output modes keep payloads small for LLMs and MCP.
- ⚡ **Fast & low-cost** — plain HTTP with no browser overhead, so large runs stay cheap.
- 💸 **Pay per result** — only pay for what you actually scrape.

### How to scrape Saramin

1. Open the actor and enter a **search keyword** (e.g. `개발자`) and/or pick filters like location, experience level, or employment type — or paste a Saramin URL.
2. Set **Max results** and choose whether to **fetch full details** (salary, qualifications, benefits, contacts, company intel).
3. (Optional) Turn on **incremental mode** and a **notification** channel, then **Schedule** it.
4. Click **Start**.
5. Download the data as **JSON, CSV or Excel**, or pull it from the **API**.

New to Apify? Create a free account — it comes with monthly credit, no credit card required.

### Input

Configure it in the visual editor — no code needed — or pass JSON via the API.

| Field | What it does |
|---|---|
| `query` | Keyword search in Korean or English (comma-separate for multiple searches). |
| `startUrls` | Scrape specific Saramin search or detail URLs. |
| `location` | Filter by South Korean region (Seoul, Gyeonggi, Busan, Jeju and 14 more). |
| `experienceLevel` | Entry-level, experienced, both, or no-experience-required. |
| `educationLevel` | High school through doctorate, or no requirement. |
| `employmentType` | Full-time, contract, internship, part-time, temporary, or freelance. |
| `minAnnualSalary` | Only postings advertising at least this annual salary. |
| `remoteOnly` | Show only remote-work (재택근무) postings. |
| `includeDetails` | Fetch each job's detail page for salary, qualifications, benefits, contacts, and company intel. |
| `incrementalMode` | Emit only what changed since the last run. |
| `maxResults` | Cap the number of records (0 = unlimited). |

...and **30 inputs** in total — the table shows the essentials; the rest cover notification channels, output/AI modes, sort order, exclude keywords, and advanced tuning, all in the visual editor.

#### Example input

```json
{ "query": "개발자", "maxResults": 100 }
```

```json
{ "query": "python, 데이터분석", "location": ["101000"], "experienceLevel": "entry", "includeDetails": true }
```

```json
{ "query": "마케팅", "incrementalMode": true, "telegramToken": "BOT_TOKEN", "telegramChatId": "-100123456789" }
```

### Output

Each job is pushed to the run's default dataset. Example record (abridged):

```json
{
  "id": "54735640",
  "title": "[수산인더스트리] 신입 IT 개발자 모집 (계약직)",
  "url": "https://www.saramin.co.kr/zf_user/jobs/view?rec_idx=54735640",
  "company": "(주)수산인더스트리",
  "companyUrl": "https://www.saramin.co.kr/zf_user/company-info/view?csn=...",
  "companyAffiliate": "수산",
  "location": "서울 강남구",
  "experienceLevel": "신입",
  "educationLevel": "고교졸업 이상",
  "employmentType": "계약직",
  "salary": "면접 후 결정",
  "applicationDeadline": "2026.08.30 23:59",
  "postedDate": "2026-08-13",
  "jobCategoryTags": ["기술지원", "백엔드/서버개발", "앱개발", "웹개발", "웹마스터"],
  "badge": "평균연봉 6,000 이상",
  "qualifications": "• (핵심역량) 빠른 실행력과 문제해결 능력 • (핵심역량) 바이브코딩 경험을 바탕으로 ...",
  "preferredQualifications": "• (우대사항) 풀스텍 개발 경험 보유자",
  "benefits": "건강검진, 각종 경조사 지원, 단체 상해보험, 자녀학자금, 기숙사 운영, ...",
  "applicationMethod": "사람인 입사지원",
  "contactName": "이민기 (경영지원팀)",
  "phoneNumber": "02-2017-8127",
  "ceoName": "한봉섭/정보윤",
  "companyType": "코스피",
  "companyIndustry": "일반전기 공사업",
  "companySize": "1,077 명 (2026년 기준)",
  "description": "[수산인더스트리] 신입 IT 개발자 모집 (계약직) — 📋 주요업무 • 사내 시스템 및 서비스의 설계 / 개발 / 운영 ...",
  "source": "saramin.co.kr",
  "country": "KR",
  "scrapedAt": "2026-08-19T18:05:07.113827+00:00"
}
```

Descriptions are available as plain text, HTML, and Markdown. The record above is trimmed for readability — a full record includes all 43 fields.

#### What data can you extract from Saramin?

- **Core** — id, title, url, company, companyUrl, companyAffiliate, location, experienceLevel, educationLevel, employmentType, salary, applicationDeadline, postedDate, jobCategoryTags, badge.
- **Detail enrichment** (with `includeDetails`) — qualifications, preferredQualifications, benefits, postingStartDate, applicationMethod, description / descriptionHtml / descriptionMarkdown.
- **Contacts & signals** — contactName, phoneNumber, extractedEmails, extractedPhones, extractedUrls, socialProfiles.
- **Company intelligence** — ceoName, companyType, companyIndustry, companySize.
- **Tracking & metadata** — source, country, searchKeyword, scrapedAt, detailFetched, contentHash, changeType, isRepost, repostOfId, repostDetectedAt.

Every field is present in standard mode (missing values are `null`); **compact mode** returns only: id, title, url, company, location, salary, experienceLevel, employmentType, applicationDeadline, source, country, scrapedAt, changeType.

With **`excludeEmptyFields`** enabled, `null`/empty fields are omitted entirely.

### Use cases

- **Lead generation** — build recruiter and hiring-manager contact lists from Korean job postings, filtered by industry, region, or company size.
- **Market & competitive research** — track hiring trends across Korean industries, compare salary ranges, and map which companies are growing.
- **Job monitoring** — schedule it with incremental mode and notifications for a live feed of new, updated, or expired postings matching your search.
- **Recruitment intelligence** — aggregate qualifications, benefits, and company profiles to benchmark your own job postings against the market.
- **Enrichment & aggregation** — feed clean, structured Korean job data into your own app, spreadsheet, or data warehouse.
- **AI agents & pipelines** — compact output plugs straight into LLM/MCP workflows for automated Korean labor-market analysis.

### Incremental monitoring — pay for changes, not repeats

Schedule the actor and turn on **incremental mode**: each run compares against the last and emits only **NEW / UPDATED / EXPIRED** records — unchanged items are skipped *before* their detail page is fetched, so a daily watch costs a fraction of a full re-scrape.

Every record gets a `changeType` field:

| `changeType` | Meaning | Returned by default? |
|---|---|---|
| `NEW` | Seen for the first time | ✅ Yes |
| `UPDATED` | Content changed since last run | ✅ Yes |
| `EXPIRED` | Disappeared since last run | Only if `emitExpired` |
| `UNCHANGED` | No change since last run | Only if `emitUnchanged` |

| Daily churn | of 1,000 tracked | billable records | you save |
|---|---|---|---|
| 5 % | 1,000 | 50 | **95 %** |
| 15 % | 1,000 | 150 | **85 %** |
| 30 % | 1,000 | 300 | **70 %** |

The first run seeds the baseline and bills in full; every run after that bills only the delta. Reposts are flagged with `isRepost`, `repostOfId`, and `repostDetectedAt`.

### Notifications

Get alerted the moment matching jobs appear. Fill in only the channels you want; each fires independently when a run finishes and there are matching jobs.

| Channel | What you provide | Where it posts |
|---|---|---|
| **Telegram** | `telegramToken` (from @BotFather) + `telegramChatId` | Your chat/channel |
| **Slack** | `slackWebhookUrl` (an incoming webhook) | That webhook's channel |
| **Discord** | `discordWebhookUrl` (a channel webhook) | That channel |
| **Webhook** | `webhookUrl` (+ optional `webhookHeaders`) | A JSON `POST` to your URL |

The generic webhook receives a structured JSON payload after every run, so you can wire the actor into any tool — n8n, Make, Zapier, or WhatsApp via a bridge. Add `webhookHeaders` (e.g. an `Authorization` header) if your endpoint needs them. Credentials are stored as secret inputs (encrypted, hidden in the UI and logs).

Pair with `incrementalMode` to be alerted only about new and changed jobs on scheduled runs.

### Integrations & export

Export to **JSON, CSV, Excel** or an HTML table, or pull from the **REST API** and the **JavaScript / Python** clients. Runs on a **schedule**, connects to **Google Sheets, Slack, Make, Zapier and n8n**, and works as an **MCP tool** for AI agents — compact mode keeps token usage small.

### Pricing

This actor uses **pay-per-event** pricing: a small per-run start fee plus a small fee per job record. You only pay for the jobs you actually receive — and with incremental mode on, only for the ones that changed.

### FAQ

**Do I need a proxy or login?** No — it runs out of the box with no proxy and no login required. Apify Proxy is available under Advanced for high-volume runs.

**Can I search in Korean and English?** Yes — the `query` field accepts both Korean (한국어) and English keywords. Separate multiple searches with commas.

**What is detail enrichment?** When `includeDetails` is on (the default), the scraper fetches each job's detail page to extract salary, qualifications, preferred qualifications, benefits, recruiter contact details, company intelligence, and the full job description. Turn it off for faster, cheaper listing-only runs.

**Can I get only new items on a schedule?** Yes — turn on incremental mode and schedule it; each run emits only what changed and can notify your Telegram, Slack, Discord, or webhook channel.

**What formats can I export?** JSON, CSV, Excel, HTML table, or via the API.

**Is it good for AI agents?** Yes — enable compact mode; the output is MCP-friendly and keeps token counts low.

**How many records can I get?** Set `maxResults` to the number you need, or set it to 0 for unlimited (up to 20,000 per run).

**Is scraping Saramin legal?** This actor accesses only publicly available data on saramin.co.kr. You are responsible for how you use the extracted data — in particular any personal information — and for complying with the site's terms and applicable law (including Korea's PIPA and the GDPR where they apply). Not affiliated with, endorsed by, or sponsored by Saramin Co., Ltd.

***

**Keywords:** saramin scraper · saramin api · saramin.co.kr scraper · 사람인 scraper · saramin jobs scraper · korean job board scraper · south korea job scraper · korea job listings · saramin salary data · scrape saramin jobs · job monitoring korea · korean recruitment data · saramin data export · export to CSV Excel JSON · no-code scraper · MCP tool for AI agents · saramin job data

# Actor input Schema

## `query` (type: `string`):

Keywords to search for (Korean or English). Separate multiple searches with commas — each runs as its own search and results are merged and de-duplicated. Leave empty to browse the newest listings.

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

Paste Saramin search or job detail URLs to scrape directly.

## `maxResults` (type: `integer`):

Maximum number of records to return. Set 0 for unlimited.

## `ignoreUrlFailures` (type: `boolean`):

Skip URLs that cannot be interpreted instead of failing the whole run.

## `location` (type: `array`):

Filter by South Korean region. Select one or more regions.

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

Filter by experience requirement.

## `educationLevel` (type: `string`):

Filter by minimum education requirement.

## `employmentType` (type: `string`):

Filter by employment type.

## `minAnnualSalary` (type: `string`):

Only show postings advertising at least this annual salary (in 만원 = 10,000 KRW units). Only postings with a published salary are affected.

## `remoteOnly` (type: `boolean`):

Only show postings that allow remote work (재택근무).

## `excludeKeyword` (type: `string`):

Exclude results containing this keyword.

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

How Saramin orders the results.

## `requireContact` (type: `string`):

Keep only records that include a contact. off = keep everything; email / phone = require that channel; either = at least one; both = email and phone.

## `includeDetails` (type: `boolean`):

Fetch each job's detail page for salary, qualifications, benefits, contact info, and full description. Turn off for the fastest, cheapest runs.

## `descriptionFormat` (type: `string`):

Which representation(s) of the job description to include.

## `compact` (type: `boolean`):

Emit only the core fields. Ideal for AI agents and MCP clients.

## `excludeEmptyFields` (type: `boolean`):

Remove null, empty-string and empty-array fields from each record.

## `incrementalMode` (type: `boolean`):

Track state between runs and tag every record with a changeType (NEW / UPDATED / UNCHANGED / EXPIRED).

## `stateKey` (type: `string`):

Stable name for the tracked search. Leave empty to derive one automatically from your search settings.

## `emitUnchanged` (type: `boolean`):

Also emit records that have not changed since the previous run.

## `emitExpired` (type: `boolean`):

Emit records for items present last run but gone now.

## `telegramToken` (type: `string`):

Bot token from @BotFather.

## `telegramChatId` (type: `string`):

Chat or channel ID, e.g. "-100123456789" or "@yourchannel".

## `slackWebhookUrl` (type: `string`):

Slack incoming-webhook URL.

## `discordWebhookUrl` (type: `string`):

Discord incoming-webhook URL.

## `webhookUrl` (type: `string`):

Any HTTPS endpoint. Receives a JSON POST with the matched records — works with n8n, Make and Zapier.

## `webhookHeaders` (type: `object`):

Extra headers for the webhook request, e.g. {"Authorization": "Bearer xyz"}.

## `notificationLimit` (type: `integer`):

How many records to include in each notification message.

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

Optional. Saramin serves plain HTML with no anti-bot protection — no proxy needed by default.

## `maxRequestRetries` (type: `integer`):

How many times to retry a failed request before giving up on it.

## Actor input object example

```json
{
  "query": "개발자, python",
  "maxResults": 25,
  "ignoreUrlFailures": true,
  "experienceLevel": "any",
  "educationLevel": "any",
  "employmentType": "any",
  "minAnnualSalary": "",
  "remoteOnly": false,
  "sortBy": "relation",
  "requireContact": "off",
  "includeDetails": true,
  "descriptionFormat": "all",
  "compact": false,
  "excludeEmptyFields": false,
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "notificationLimit": 5,
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "maxRequestRetries": 3
}
```

# Actor output Schema

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

No description

## `allItems` (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 = {
    "query": ""
};

// Run the Actor and wait for it to finish
const run = await client.actor("corvuslab/saramin-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 = { "query": "" }

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,corvuslab/saramin-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/Hscm4ekcqzhHWGz1h/builds/AIdDdjyZGOh0GMHsn/openapi.json
