# Eleduck (电鸭社区) Jobs & Posts Scraper (`lxlsj/eleduck-jobs-scraper`) Actor

Scrape remote job listings and community posts from eleduck.com — China's largest remote-work community. Full text, tags, author, engagement metrics. No login required.

- **URL**: https://apify.com/lxlsj/eleduck-jobs-scraper.md
- **Developed by:** [John](https://apify.com/lxlsj) (community)
- **Categories:** Jobs, AI, Automation
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## Eleduck Jobs Scraper — China Remote Jobs

**Get structured remote-job data out of China's biggest remote-work community.**

[Eleduck (电鸭社区)](https://eleduck.com) is where Chinese developers, designers and product people actually look for remote work. Its jobs board holds **11,000+ listings across 447 pages** — real salaries, real companies, updated daily. There's no public export, no RSS, and the jobs page itself sits behind a CAPTCHA.

This Actor turns that board into clean JSON.

```json
{
  "title": "Remote（AI agent方向）-AI工程师、后端工程师、开发者关系工程师",
  "url": "https://eleduck.com/posts/XNfwom",
  "work_arrangement": ["全职远程"],
  "job_function": ["AI工程师"],
  "hiring_type": ["企业直招"],
  "industry": ["AI/人工智能"],
  "salary_min": 20000,
  "salary_max": 60000,
  "salary_currency": "CNY",
  "salary_period": "month",
  "salary_min_cny_month": 20000,
  "salary_max_cny_month": 60000,
  "salary_raw": "20k-60k",
  "published_at": "2026-07-06T14:10:28+08:00",
  "views_count": 888,
  "comments_count": 21,
  "matched_filter": "全职远程 + AI工程师",
  "content_markdown": "## 公司介绍\n\nAIsa 成立于 2025 年..."
}
```

41 fields per job. Full description in Markdown *and* HTML. Ready to load into a database, a spreadsheet, or an LLM prompt.

***

### Three things that make this different

#### 1. Multi-select filters — something the website itself can't do

Eleduck lets you pick **one** value per filter. Want AI engineers *and* developers? Full-time remote *and* part-time? You're running searches by hand and merging them yourself.

This Actor takes your selections, runs every combination, and hands back one deduplicated dataset:

```json
{
  "jobTypes":   ["19", "18"],
  "skillTypes": ["162", "10"]
}
```

```
→ 全职远程 + AI工程师      31 jobs
→ 全职远程 + 开发       5,089 jobs
→ 线上兼职 + AI工程师      34 jobs
→ 线上兼职 + 开发       2,927 jobs
   deduplicated into a single clean output
```

Every record carries `matched_filter`, so you always know which combination surfaced it. Five filter groups, 48 options total, all multi-select:

| Group | Options |
|---|---|
| **Work arrangement** | Full-time remote · On-site · Part-time online · Part-time on-site · Hybrid |
| **Job function** | AI engineer · Developer · Product · Design · Ops · Writing · DevOps · Other |
| **Hiring type** | Direct employer · Outsourced gig · Referral · Co-founder · Recruiter |
| **City** | Overseas · Beijing · Shanghai · Shenzhen · Hangzhou … (18) |
| **Industry** | AI · SaaS · Open source · Media · E-commerce · Web3 … (12) |

#### 2. Salaries you can actually sort by

Chinese job posts write pay however they feel like it. This Actor parses it anyway:

```
薪资35-42K          →  35,000 – 42,000 CNY/month
18K - 35K / 月      →  18,000 – 35,000 CNY/month
年薪20W-30W         → 200,000 – 300,000 CNY/year  → 16,667–25,000/month
500～1500 美元/月    →     500 –   1,500 USD/month →  3,600–10,800 CNY
1.5万-2.5万         →  15,000 – 25,000 CNY/month
预算300–600/月       →     300 –     600 CNY/month
```

Half-width and full-width dashes, `～`, thousands separators, K/千/W/万, five currencies, four pay periods — all normalised into `salary_min_cny_month` / `salary_max_cny_month`. **One column you can sort across every format.**

**And it refuses to guess.** These all return no salary rather than a wrong number:

```
2-3个真实实操案例        项目周期：约 2 - 3 周      从 0 到 1 做一个长期项目
70%基础薪资              1 - 3 年经验              填 10 分钟问卷
```

Every false positive above was found by checking output against live data by hand, then locked down with a test. 34 unit tests, all passing. Roughly **half of real posts** yield a parseable salary — the rest genuinely say "面议" (negotiable). `has_salary` tells you which, and `salary_source_line` shows the exact line every number came from, so you can verify any of it yourself.

#### 3. No browser, no CAPTCHA, no proxies

The jobs page redirects humans to an Aliyun CAPTCHA. This Actor doesn't touch it — it reads the JSON API directly. No login, no cookies, no headless Chrome.

That means **~13 seconds and 0.014 compute units** for a typical run, and nothing to break when the site restyles its frontend.

***

### Works out of the box

Hit Start and you get recent AI/automation jobs immediately. Defaults are pre-filled with `AI Agent`, `RAG`, `邮件分类`, `客服系统`, `自动化`, `爬虫` and a **rolling 60-day window** — recalculated every run, so a scheduled task never drifts into stale data. Clear or change any of it.

#### Common setups

**Daily AI-jobs digest** — schedule it, get only what's new:

```json
{
  "skillTypes": ["162"],
  "lastDays": 1,
  "fetchFullContent": true
}
```

Paging stops the moment it crosses your cutoff, so incremental runs cost a handful of requests.

**Senior roles only, salary stated:**

```json
{
  "jobTypes": ["19"],
  "minMonthlySalaryCny": 25000,
  "requireSalary": true
}
```

**Everything, no filters** — all 11,000+ jobs:

```json
{ "maxItems": 0, "lastDays": 0 }
```

***

### Input

| Option | Default | What it does |
|---|---|---|
| **board** | Jobs Channel | Jobs Channel (11,000+ structured listings) or Community posts (20,000+) |
| **jobTypes** | — | Work arrangement. Multi-select |
| **skillTypes** | — | Job function. Multi-select |
| **hireTypes** | — | Hiring type. Multi-select |
| **cities** | — | Location. Multi-select |
| **fields** | — | Industry. Multi-select |
| **maxItems** | 100 | Cap results. `0` = no limit |
| **fetchFullContent** | true | Fetch full description (1 request per job). Off = 25 jobs per request, metadata only |
| **lastDays** | 60 | Rolling window in days. `0` = disable |
| **publishedAfter** | — | Absolute cutoff (`YYYY-MM-DD`) if you need one |
| **keywords** | pre-filled | Keep posts matching ANY keyword |
| **minMonthlySalaryCny** | 0 | Minimum monthly pay in CNY, currencies normalised first |
| **requireSalary** | false | Drop posts with no stated salary |
| **excludeClosed** | true | Skip filled positions |
| **sort** | Newest | Newest or Hottest |

Advanced settings cover request delay, concurrency and proxy. The defaults are tested — you shouldn't need them.

### Output

41 fields per job:

**Identity** — `id` · `url` · `title` · `published_at` · `modified_at`
**Structured tags** — `work_arrangement` · `job_function` · `hiring_type` · `city` · `industry` · `all_tags`
**Salary** — `salary_min` · `salary_max` · `salary_currency` · `salary_period` · `salary_min_cny_month` · `salary_max_cny_month` · `salary_raw` · `salary_source_line` · `has_salary`
**Content** — `content_markdown` · `content_html` · `content_text` · `summary`
**Signals** — `views_count` · `comments_count` · `upvotes_count` · `is_closed` · `is_featured` · `is_pinned`
**Poster** — `author_nickname` · `author_level` · `author_roles`
**Provenance** — `matched_filter` · `scraped_at`

Also available as CSV, Excel, XML or RSS through the Apify API — and every run exposes a `runSummary` reporting what each filter combination matched and why anything was skipped.

### Cost

Pure HTTP, so runs are cheap:

| Mode | Requests |
|---|---|
| Metadata only | 1 per **25 jobs** |
| With full descriptions | 1 per job |
| Daily incremental (`lastDays: 1`) | a handful |

A 25-job run with full text: **~13 seconds, 0.014 CU**.

### Built for

- **Job boards & aggregators** — syndicate China remote listings
- **Recruiters** — track who's hiring, at what pay, in your niche
- **AI agents** — output schema is defined, so agents can chain this Actor via MCP or API without guessing the shape
- **Market researchers** — salary benchmarks and hiring-demand trends by role and industry
- **Job seekers** — a filtered feed instead of refreshing a page

### Notes

Public data only. No emails, phone numbers or contact details are collected, in line with Apify's personal-data policy. Public nicknames and engagement counts are included.

Only English-language field names are used; job content stays in its original language (mostly Chinese, some English).

Questions or a field you need? Open an issue on the Actor page.

# Actor input Schema

## `board` (type: `string`):

Jobs Channel (招聘专区) has 11,000+ structured job posts with rich filters — recommended. Community posts is the free-form discussion board.

## `jobTypes` (type: `array`):

Pick one or more. Selecting multiple runs a separate query per combination and merges + deduplicates the results — the website itself only supports one at a time.

## `skillTypes` (type: `array`):

Pick one or more. Combined with Work arrangement as a cross-product (e.g. 2 arrangements x 2 functions = 4 queries, deduplicated).

## `hireTypes` (type: `array`):

Who is hiring: direct employer, outsourced gig, employee referral, co-founder search, or recruiter. Multi-select expands into separate queries.

## `cities` (type: `array`):

Job location. 海外 = overseas. Remote roles often leave this empty, so use it together with Work arrangement rather than instead of it.

## `fields` (type: `array`):

Industry / domain of the hiring company. Multi-select expands into separate queries.

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

Total across all filter combinations, after deduplication. 0 = unlimited.

## `fetchFullContent` (type: `boolean`):

Fetch complete post body (HTML + Markdown) — salary, requirements, contact info. Costs 1 extra request per post.

## `lastDays` (type: `integer`):

Relative window, recalculated on every run — 60 means the last 60 days from today, so scheduled runs never go stale. Set 0 to disable. Paging stops at the cutoff, which makes daily incremental runs very cheap.

## `publishedAfter` (type: `string`):

Absolute cutoff date (YYYY-MM-DD). Optional — normally just use the N-days field above. If both are set, the stricter (later) one wins.

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

Keep only posts whose title or summary contains ANY of these (OR logic). Pre-filled with common AI/automation topics — edit or clear as needed.

## `minMonthlySalaryCny` (type: `integer`):

Only keep jobs whose parsed max salary reaches this monthly CNY figure. Yearly/hourly rates and foreign currencies are normalised automatically. Jobs with no parseable salary are kept unless you enable the option below.

## `requireSalary` (type: `boolean`):

Drop posts where no salary could be parsed from the text.

## `excludeClosed` (type: `boolean`):

Skip positions the poster has already marked as filled. Recommended — closed jobs are dead leads.

## `sort` (type: `string`):

Newest first is best for incremental daily runs; Hottest surfaces the most-viewed posts.

## `minRequestDelayMs` (type: `integer`):

Eleduck rate-limits aggressively — keep >= 500.

## `maxConcurrency` (type: `integer`):

Tested: 5+ triggers rate limiting (server returns HTML). 3 is stable.

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

Eleduck is China-hosted and usually works without proxy.

## Actor input object example

```json
{
  "board": "jobs_channel",
  "jobTypes": [],
  "skillTypes": [],
  "hireTypes": [],
  "cities": [],
  "fields": [],
  "maxItems": 100,
  "fetchFullContent": true,
  "lastDays": 60,
  "publishedAfter": "",
  "keywords": [
    "AI Agent",
    "RAG",
    "邮件分类",
    "客服系统",
    "自动化",
    "爬虫"
  ],
  "minMonthlySalaryCny": 0,
  "requireSalary": false,
  "excludeClosed": true,
  "sort": "new",
  "minRequestDelayMs": 600,
  "maxConcurrency": 3,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

One record per job: title, URL, structured tags (work arrangement, job function, city, industry), parsed salary normalised to monthly CNY, and the full description in Markdown and HTML.

## `runSummary` (type: `string`):

OUTPUT\_SUMMARY key: how many jobs matched per filter combination, counts of records skipped (closed, too old, keyword mismatch, duplicate, salary below threshold), and the settings used.

# 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 = {
    "lastDays": 60,
    "keywords": [
        "AI Agent",
        "RAG",
        "邮件分类",
        "客服系统",
        "自动化",
        "爬虫"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("lxlsj/eleduck-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 = {
    "lastDays": 60,
    "keywords": [
        "AI Agent",
        "RAG",
        "邮件分类",
        "客服系统",
        "自动化",
        "爬虫",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("lxlsj/eleduck-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 '{
  "lastDays": 60,
  "keywords": [
    "AI Agent",
    "RAG",
    "邮件分类",
    "客服系统",
    "自动化",
    "爬虫"
  ]
}' |
apify call lxlsj/eleduck-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,lxlsj/eleduck-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/42h9NurHXKnBvGyhX/builds/RCMW5RaS5Y1HwL303/openapi.json
