"Four Remote Job Boards Have Free Public APIs. Here Is One Schema for All of Them"

Four Remote Job Boards Have Free Public APIs. Here Is One Schema for All of Them

四个提供免费公共 API 的远程工作招聘网站,以及一套通用的数据架构

If you want remote job data, you do not need to scrape HTML or sign up for anything. Four of the bigger remote job boards publish keyless public feeds. The catch is that they all speak different dialects, so the real work is normalization. Here are the endpoints and the traps. 如果你需要远程工作的数据,完全不需要去抓取 HTML 或注册任何账号。目前有四个大型远程招聘网站提供无需密钥的公共数据源。难点在于它们的数据格式各不相同,因此真正的挑战在于如何进行标准化处理。以下是这些接口地址及需要注意的坑。

The four feeds

四个数据源

RemoteOK returns its whole current board as one JSON array: GET https://remoteok.com/api. The first element is a legal notice, not a job: they ask for a link back with attribution as a condition of using the feed. Skip element zero, and honor the attribution if you republish. Jobs carry salary_min and salary_max as numbers, tags, and ISO dates. RemoteOK 将其当前所有的招聘信息作为一个 JSON 数组返回:GET https://remoteok.com/api。数组的第一个元素是法律声明而非职位信息:他们要求在使用该数据源时必须提供回链并注明出处。请跳过第一个元素,并在重新发布时遵守署名要求。职位信息中包含以数字形式表示的 salary_minsalary_max、标签以及 ISO 格式的日期。

Remotive has the friendliest API of the four, including server side search: GET https://remotive.com/api/remote-jobs?search=python&limit=100. Salary here is free text (“$120k - $160k”), so do not expect numbers. Attribution with a link back is required here too. Remotive 是这四个中 API 最友好的,支持服务端搜索:GET https://remotive.com/api/remote-jobs?search=python&limit=100。这里的薪资是自由文本(例如 “$120k - $160k”),所以不要指望得到数字格式。同样,这里也要求提供回链署名。

WeWorkRemotely publishes RSS: GET https://weworkremotely.com/remote-jobs.rss. Two quirks: the company name is not a field, it is baked into the title as “Company: Role”, so split on the first colon. And useful data hides in nonstandard tags like <region>, <skills>, and <category> that generic RSS parsers drop on the floor. WeWorkRemotely 提供 RSS 源:GET https://weworkremotely.com/remote-jobs.rss。有两个小怪癖:公司名称不是一个独立字段,而是嵌入在标题中(格式为 “Company: Role”),因此需要按第一个冒号进行分割。此外,有用的数据隐藏在 <region><skills><category> 等非标准标签中,通用的 RSS 解析器通常会忽略这些标签。

Himalayas has a proper paginated API with a surprisingly deep catalog (100k+ listings): GET https://himalayas.app/jobs/api?limit=100&offset=0. It gives structured minSalary/maxSalary with a currency and period, seniority arrays, location restrictions, and even timezone restrictions as UTC offsets. Dates are epoch seconds, not ISO strings. Himalayas 提供了一个规范的分页 API,且拥有非常庞大的数据库(超过 10 万条列表):GET https://himalayas.app/jobs/api?limit=100&offset=0。它提供结构化的 minSalary/maxSalary(包含货币和周期)、资历数组、地理位置限制,甚至是以 UTC 偏移量表示的时区限制。日期格式为 Unix 时间戳(秒),而非 ISO 字符串。

The normalization layer

标准化层

The row schema that survived contact with all four sources: 经过与这四个数据源的对接,最终确定的数据架构如下:

{
  "source": "Remotive",
  "title": "Senior Backend Engineer",
  "company": "Acme Corp",
  "tags": ["python", "aws"],
  "salaryMin": null,
  "salaryMax": null,
  "salaryText": "$120k - $160k",
  "location": "Worldwide",
  "postedAt": "2026-07-03T20:01:13.000Z",
  "applyUrl": "https://..."
}

Rules that mattered in practice: 实践中需要遵循的规则:

  • Keep both salary shapes. Boards with numbers fill salaryMin/salaryMax; boards with prose fill salaryText. Collapsing one into the other loses information either way. 保留两种薪资格式。 提供数字的网站填充 salaryMin/salaryMax;提供文本描述的网站填充 salaryText。强行将两者合并会导致信息丢失。
  • Normalize every date to ISO 8601 at the edge. Epoch seconds, RFC 822 RSS dates, and ISO strings all flow through one converter, so downstream code never branches on source. 在入口处将所有日期标准化为 ISO 8601 格式。 无论是 Unix 时间戳、RFC 822 RSS 日期还是 ISO 字符串,都通过同一个转换器处理,这样下游代码就不需要针对不同的数据源编写分支逻辑。
  • Dedupe on lowercased title|company. Companies cross-post to multiple boards, and the same listing showing up four times makes the feed look broken. 使用小写的“标题|公司名”进行去重。 公司通常会在多个平台发布同一职位,如果同一条信息出现四次,会显得数据源很混乱。
  • Carry source and sourceUrl on every row. It satisfies the attribution requirements and it turns out buyers of job data want to know provenance anyway. 每一行都要携带 source 和 sourceUrl。 这既满足了署名要求,而且事实证明,招聘数据的买家也确实需要了解数据的来源。

What this is good for

这些数据的用途

The obvious build is a job alert pipeline: run it hourly with keywords, diff against what you have seen, push new rows to Slack. The less obvious one is sales intelligence: a company hiring for a role is telling you what they are about to spend money on, and job feeds are the earliest public signal of that. 最显而易见的用途是构建一个职位提醒流水线:每小时用关键词运行一次,与已有的数据进行对比,并将新职位推送到 Slack。不太明显的用途是销售情报:一家公司招聘某个职位,意味着他们准备在相关领域投入资金,而招聘信息正是这一动向最早的公开信号。

I packaged the whole thing (four fetchers, normalization, dedupe, keyword and freshness filters) into an actor on Apify if you want it as a scheduled feed. But every endpoint above works with nothing more than fetch, and the boards deserve the link backs their terms ask for. 如果你需要定时抓取,我已经将整套逻辑(四个抓取器、标准化、去重、关键词和时效性过滤)封装成了 Apify 上的一个 Actor。但上述每个接口仅通过简单的 fetch 即可调用,且请务必遵守各网站的服务条款,提供应有的回链。