

# 如何把已核对的职位行转成 RSS 订阅源

把已核对的职位行转成 RSS 2.0 订阅源。给每个条目一个稳定 ID 和原始职位链接。对文本编码，使订阅源保持有效。仅当源时间和时区都已知时，才添加发布日期。

RSS 表示 Really Simple Syndication。它是订阅阅读器可以打开的一种文档格式。RSS 用 XML 书写。XML 是结构化文本。

## 使用你已经核对过的行

Actor 是托管的数据采集程序。Task 是已保存的输入预设。[Indeed Jobs Scraper](https://apify.com/chronometrica/indeed-jobs-scraper) Actor 采集源行。你用已经核对过的行来写 RSS 订阅源。该 Actor 不会替你写这个订阅源。

Indeed 是这些行的来源招聘网站。公开构建版本 1.2.14 可以返回本方法使用的行字段。这些字段是 jobId、jobUrl、title、companyName、descriptionText、descriptionStatus、postedAt、postedAtRaw 和 scrapedAt。jobUrl 是该职位的网址。网址也称为 URL。

一项两行对照接受了源 ID、源 URL 和完整描述文本。该对照的上限是两行。有限样本并不是该网站上的全部职位。本方法不修复被阻断的 Upwork 采集。它也不创建 Indeed 原生订阅源。

当前公开的 [Indeed Jobs Scraper Task](https://apify.com/chronometrica/indeed-jobs-scraper/examples/indeed-jobs-scraper) 已于 2026-10-13T05:55:51.545104+00:00 核对。它保存的输入是：

```json
{"country": "us", "searchTerm": "software engineer", "maxItems": 100, "postedWithinDays": "7", "sortBy": "date", "maxPagesPerSearch": 2, "saveOnlyUniqueItems": true}
```

使用你已经核对过的行

只把该输入当作起点。采集行时，替换示例搜索词。也替换国家或地点。maxItems 100 限制的是请求。它不是找到的职位数量。maxPagesPerSearch 2 限制一次搜索的页数。它不是全站覆盖。saveOnlyUniqueItems true 要求采集保留互不相同的条目。写订阅源之前，你仍要核对 ID。公开的 Task 并不表示订阅源工作会自动完成。

采集、行比较和[身份复核](/zh-Hans/articles/%E5%8E%BB%E9%99%A4%E9%87%8D%E5%A4%8D%E8%81%8C%E4%BD%8D%E5%88%97%E8%A1%A8-%E5%BD%92%E7%BB%84%E5%8F%AF%E8%83%BD%E7%9A%84%E9%87%8D%E6%96%B0%E5%8F%91%E5%B8%83/)都在本方法之前。这里的身份是指一条招聘信息的稳定源 ID。只从一组有限的已核对行开始。当某行的 ID 缺失或仍在复核中时，排除该行。

## 分八步构建订阅源

1. 确定样本和目的。

目的是给订阅阅读器一份由已核对招聘信息组成的有效文档。从具有已知 ID 的有用行开始。同时保留一份覆盖记录。覆盖记录是一份简短说明，写明订阅源包含哪些行。排除缺失的 ID。排除仍在复核中的 ID。

1. 选择条目身份规则。

对一条 Indeed 招聘信息，键是文本 indeed: 紧接着 jobId。GUID 是条目身份字符串。GUID 表示全局唯一标识符。RSS 把它存在 guid 元素中。把 isPermaLink 设为 false。false 表示该 GUID 不是网址。标题变化时，保持同一个 GUID。描述变化时，保持同一个 GUID。在此规则下，新的源 ID 会生成新的订阅源条目。新的源 ID 并不能证明这是雇主的一个新职位。需要匹配同一职位时，使用单独的方法。

1. 创建一份只含一个 channel 的 RSS 2.0 订阅源。

根元素是 rss，其 version 是 2.0。在其中放入一个 channel。channel 是容纳订阅源标题及其条目的主分组。item 是订阅源中的一条职位信息。[RSS 规范](https://www.rssboard.org/rss-specification) 要求 channel 有 title、link 和 description。三者都要给出。为每一条有用的行添加一个 item。给该 item 一个 title。把它的 link 设为原始职位网址。给它一段简短 description。同一规范要求每个 item 有 title 或 description。本方法两者都给。让 channel 的 link 对你的阅读器保持可访问。

1. 用 XML 序列化器写入文本。

这一写入步骤称为序列化。不要用手把原始职位文本粘贴进文件。和号或小于号会破坏 XML。[XML 语法规则](https://www.w3.org/TR/xml/#syntax) 说明这些字符必须如何书写。序列化器是把文本写成安全 XML 形式的程序。它保留 Unicode 字母，例如 é。它保留网址中的查询文本。查询字符串是网址中问号之后的文本。安全的 XML 文本并不是安全的 HTML。HTML 是用来绘制网页的格式。序列化器不会让粘贴的 HTML 可以安全显示。在 item 中使用纯文本摘要。把完整职位文本留在原始职位页面。仅当你的行核对接受了 descriptionStatus 时，才使用 descriptionText。companyName 可以留在源行中。订阅源条目不要求它。

1. 仅在发布时间已确认时添加 pubDate。

pubDate 是 RSS 中条目发布日期的名称。postedAt 是可选的，并且从源文本解析而来。一个已填写的 postedAt 值并不能证明精确的发布时间。检查 postedAtRaw 和源证据。仅当发布时间和时区都已确认时，才添加 pubDate。如果时间缺失、是相对时间或不确定，它就保持不可用。相对时间，例如写着若干天前的短语，并不精确。后面的日期字符串属于原始虚构样本。[RSS 日期样式](https://www.rssboard.org/rss-specification) 的形式类似 Mon, 12 Oct 2026 09:30:00 GMT。GMT 是该样式为这一 UTC 时间使用的时区名。UTC 表示协调世界时。当发布时间未知时，不要写入 pubDate。你可以在条目摘要或覆盖记录中写明观察时间。scrapedAt 是观察时间。不要把 scrapedAt 当作发布时间。lastBuildDate 表示构建该订阅源文档的时间。仅当你单独跟踪该构建时间时，才添加 lastBuildDate。不要用构建时间去填补未知的职位日期。

1. 核对源行与订阅源条目。

核对是指比较两份列表，并交代每一行。报告你使用的已知 ID。报告你排除的行。报告仍未解决的行。报告重复的键。报告没有发布日期的条目数量。由有限数据集构建的订阅源仍然有限。后来的样本中缺少某个条目，并不能证明雇主移除了该职位。阅读器如何删除或更新条目，是另一项选择。

1. 解析订阅源，并分三层检查。

解析是指读取文档并确认其结构。第一，解析 XML。确认必需元素。确认条目数量。确认每个 GUID 都唯一。确认文本变化时每个 GUID 保持不变。确认每个条目链接。确认解析后的文本与源文本一致。确认每个日期保持其源含义。解析成功表明 XML 结构完好。它并不能证明每一条 RSS 规则。它也不能证明每个阅读器都会接受该订阅源。第二，检查你所依赖的 RSS 规则。第三，测试你计划使用的阅读器。导入是指在该阅读器中打开订阅源。在加入真实行之前，先导入一份小型虚构订阅源。把该阅读器测试与文档测试分开。

1. 保存订阅源和解释它的说明。

把覆盖说明、日期说明和源记录放在一起。源记录写明你使用了哪些已核对的行。仅当你的阅读器需要访问时，才托管该文件。托管是指把文件放在阅读器可以获取的位置。本文不发布实时订阅源。它不透露私有访问密钥。它不安排刷新。它不发送提醒。[跟踪尚未见过的职位](/zh-Hans/articles/%E4%B8%8D%E9%87%8D%E5%A4%8D%E7%9A%84%E6%96%B0%E8%81%8C%E4%BD%8D%E6%8F%90%E9%86%92/)是另一项任务。

## 阅读虚构的两条目订阅源

本节中的订阅源是原创虚构内容。它用来说明规则。它不是该 Actor 的结果。它也不能证明只存在两个职位。

样本有两条源招聘信息。它们的源 ID 是文本值 000101 和 000102。J1 和 J2 只是这两条虚构行的标签。GUID 是 indeed:000101 和 indeed:000102。J1 已确认的发布时间是 2026 年 10 月 12 日 09:30 UTC。J2 的发布时间未知，因此其发布日期不可用。

| 行 | 源 ID | GUID | 条目链接 | 发布日期 |
| --- | --- | --- | --- | --- |
| J1 | 000101 | indeed:000101 | https://jobs.example/J1?role=analyst&city=Austin | Mon, 12 Oct 2026 09:30:00 GMT |
| J2 | 000102 | indeed:000102 | https://jobs.example/J2 | 不可用 |

J1 的标题是 Café Analyst & SQL。它的描述是 Check values < 10 & explain results。J2 的标题是 Report Analyst。它的描述是 Publication time unavailable. Observed 2026-10-13 05:50 UTC。该观察时间不是发布时间。

J1 的标题测试 Unicode 和一个和号。J1 的描述测试一个小于号和一个和号。J1 的链接测试查询字符串。订阅源以安全的 XML 文本存储这些字符。

| 源文本 | 写入订阅源的文本 |
| --- | --- |
| Café Analyst & SQL | Café Analyst &amp; SQL |
| Check values < 10 & explain results. | Check values &lt; 10 &amp; explain results. |
| https://jobs.example/J1?role=analyst&city=Austin | https://jobs.example/J1?role=analyst&amp;city=Austin |

```xml
<?xml version='1.0' encoding='utf-8'?>
<rss version="2.0">
  <channel>
    <title>Fictional checked analyst sample</title>
    <link>https://jobs.example/sample</link>
    <description>Two checked sample rows; source collection was capped.</description>
    <item>
      <title>Café Analyst &amp; SQL</title>
      <link>https://jobs.example/J1?role=analyst&amp;city=Austin</link>
      <description>Check values &lt; 10 &amp; explain results.</description>
      <guid isPermaLink="false">indeed:000101</guid>
      <pubDate>Mon, 12 Oct 2026 09:30:00 GMT</pubDate>
    </item>
    <item>
      <title>Report Analyst</title>
      <link>https://jobs.example/J2</link>
      <description>Publication time unavailable. Observed 2026-10-13 05:50 UTC.</description>
      <guid isPermaLink="false">indeed:000102</guid>
    </item>
  </channel>
</rss>
```

阅读虚构的两条目订阅源

J1 对应第一个条目。它的 GUID 是 indeed:000101，它的 pubDate 是已确认的 UTC 时间。J2 对应第二个条目。它的 GUID 是 indeed:000102。日期空缺是 J2 上缺少的 pubDate。J2 的描述只写明观察时间。不要用你构建文档的时间去填补该空缺。

一项本地文档测试解析了这份 XML。它找到一个 channel 和两个 item。它确认了必需的 channel 文本。它确认两个 GUID 唯一，并且 isPermaLink 为 false。解析之后，文本与 Unicode 标题、小于号、和号以及原始查询链接一致。该测试读取了 J1 的发布日期。它确认 J2 没有 pubDate。它更改了 J1 的标题，而 GUID 仍是 indeed:000101。

这些是对此虚构样本的文档检查。XML 解析表明结构完好。GUID、链接、文本和日期检查覆盖了此处使用的 RSS 规则。没有做订阅阅读器测试。没有做 WordPress 测试。先解析你的虚构订阅源。然后在你自己的阅读器中做一次小型兼容性检查。

## 下一步

用 [Indeed Jobs Scraper](https://apify.com/chronometrica/indeed-jobs-scraper) Actor 和这个公开的 [Indeed Jobs Scraper Task](https://apify.com/chronometrica/indeed-jobs-scraper/examples/indeed-jobs-scraper) 采集已核对的行。先解析一份两条目的虚构订阅源。在把真实行导入阅读器之前，确认它的 GUID、日期和源链接。

## 来源和延伸阅读

- [RSS 2.0 规范](https://www.rssboard.org/rss-specification)
- [XML 语法](https://www.w3.org/TR/xml/#syntax)
- [Indeed Jobs Scraper Actor](https://apify.com/chronometrica/indeed-jobs-scraper)
- [Indeed Jobs Scraper 公开 Task](https://apify.com/chronometrica/indeed-jobs-scraper/examples/indeed-jobs-scraper)
- [API 与 RSS 职位导入问题](https://www.reddit.com/r/webdev/comments/1ewb7wt/api_vs_rss_feeds_for_pulling_job_listings_for_a/)
- [Indeed 抓取器问题](https://www.reddit.com/r/webscraping/comments/1bkjb1q/looking_for_indeed_scraper_easy_free/)