首页
/ 如何用 career-ops 的 check-liveness.mjs 批量验证失效的职位链接并清理 pipeline

如何用 career-ops 的 check-liveness.mjs 批量验证失效的职位链接并清理 pipeline

2026-09-08 19:35:55作者:俞予舒Fleming

在 career-ops 的求职流水线里,data/pipeline.md 的 "Pending" 区会不断累积待处理的职位 URL。其中由扫描器在 headless/batch 模式下加入的条目带有 **Verification:** unconfirmed (batch mode) 标记——因为扫描时 Playwright 不可用,它们从未做过 liveness 检查。如果直接逐条处理,失效职位会被一个一个打开、抽取 JD、消耗评估 token。modes/pipeline.md 给出的做法是:在逐 URL 循环之前,先用零 token 的 check-liveness.mjs 把所有 pending URL 批量扫一遍(liveness sweep),把失效链接从 pipeline 里清掉,再处理幸存者。

这篇文章只覆盖这一条路径:批量验证 + 按判定结果清理 pipeline。

检查器如何判定一条链接

check-liveness.mjs 对每个 URL 采用两级检查(见 check-liveness.mjsdocs/SCRIPTS.md 的 liveness 小节):

  1. API 级(零 token、无浏览器)liveness-api.mjs 先尝试公共 ATS 端点——Greenhouse、Lever、Ashby、Workday、LinkedIn。对 Greenhouse/Lever/Workday 这类单职位端点,HTTP 200 即证明职位仍在;权威的 404/410 直接判定 expired 并跳过浏览器检查。
  2. 浏览器级(回退):API 无法覆盖或结果不明确时,liveness-browser.mjs 用 headless Chromium 打开页面,检测失效模式("job no longer available" 之类的文案,支持英/德/法多语言)、HTTP 404/410、ATS 重定向模式、apply 按钮是否存在。

设计上是保守的:宁可返回 uncertain 也不轻易误判 expired,因为漏掉一个真实职位的代价更高。每个 URL 得到三种判定之一:activeexpireduncertain,附一条 reason。整个过程不消耗 LLM token。

准备条件

  • 在 career-ops 项目根目录操作,data/pipeline.md 中已有 pending 条目。
  • 先运行 npm run doctor 确认前置条件:Node.js >= 18、依赖已安装、Playwright chromium 可用、所需文件(cv.mdconfig/profile.ymlportals.yml)存在。doctor 退出码 0 表示全部通过,1 表示有失败项并打印修复提示。

第一步:把 pending URL 收集到临时文件

data/pipeline.md 的 "Pending" 区收集所有 - [ ] 行的 URL,写入一个临时文件,每行一个。--file 的解析规则(来自 check-liveness.mjs 源码):按行读取、去除首尾空白、跳过空行和 # 开头的注释行——所以临时文件里可以带注释头。

示例文件(URL 为示意,请替换为自己 pipeline 中的真实链接):

# pipeline.md pending URLs, 2026-09-08
https://boards.greenhouse.io/example-company/jobs/123456
https://jobs.lever.co/example/abc123
https://careers.example.com/posting/789

第二步:运行批量检查

node check-liveness.mjs --file urls.txt

等价的 npm 入口是 npm run liveness -- --file urls.txt。URL 数量较多时加 --throttle(默认基线 5000ms,每次等待在 base 到 2×base 之间抖动),目的是让浏览器级请求之间的间隔落在基于速率的 WAF 阈值之下——例如 pracuj.pl 的 Cloudflare 在约 2 次快速请求后就会标记会话,--throttle=5000 就是文档中给出的用法。检查是顺序执行的,且浏览器按需懒启动:所有 URL 都能被 API 级判定时,Playwright 根本不会启动。

无显示器的机器(headless 环境无法弹出有头浏览器兜底)加 --no-fallback,全程保持无头模式。

第三步:读取结果

每个 URL 打印一行判定,非 active 的附 reason,最后是一行汇总。输出格式示意(以下为文档示例,数值与 URL 以你的实际运行为准):

Checking 3 URL(s)...

✅ active     (api) https://boards.greenhouse.io/example-company/jobs/123456
❌ expired            https://jobs.lever.co/example/abc123
           HTTP 404
⚠️ uncertain          https://careers.example.com/posting/789
           navigation timeout

Results: 1 active  1 expired  1 uncertain  (1 via API, no browser)

退出码是明确的判断依据:0 表示全部 active;只要存在任何 expireduncertain,退出码就是 1。也就是说,非零退出并不意味着检查失败,而是"这批链接里有需要处理的条目"。

第四步:按判定结果清理 pipeline

modes/pipeline.md 的 Liveness sweep 对三种判定给出了明确的处理方式:

判定 处理
expired 不再处理该职位:把条目从 "Pending" 移到 "Processed",写成 - [x] ~~URL | Company | Role~~ — posting expired (liveness sweep);如果该条目已经有 tracker 行(data/applications.md),将其标记为 Discardedtemplates/states.yml 中的规范状态)。不要为其抽取 JD、执行评估或生成报告/PDF
uncertain 留在 "Pending" 原位不动,交给后续逐 URL 提取阶段确认——瞬时超时不应该直接丢掉一个可能仍然有效的职位
active 继续进入正常的逐 URL 处理流程(提取 JD → 评估 → 报告/tracker)

处理完过期条目后,可以用 npm run verify 复核 pipeline 数据完整性:它对 data/applications.md 做九条规则校验(规范状态、无重复 company+role、报告链接有效等),退出码 0 表示零错误。改动了 tracker 状态(如标 Discarded)之后跑一次是顺手的确认动作。

边界与限制

  • uncertain 不算通过。 它与 expired 一样会让整体退出码为 1,但处理方式完全不同:expired 直接清理,uncertain 保留待确认。
  • 无头浏览器可能被 WAF 拦截。 headless 请求默认会伪装成普通桌面 Chrome UA(避免 Cloudflare 类 WAF 直接出挑战页);遇到仍无法通过的反爬墙时,检查器会重试一次有头浏览器。--no-fallback 下不做这次重试,可能得到更多 uncertain
  • 批量节流只作用于浏览器级请求之间,API 级请求本身廉价且不计入节流。
  • verify:portals 的区别。 npm run verify:portals 探测的是 portals.yml 里各公司 ATS slug 是否还能解析(board 级),本文的 liveness sweep 针对的是 data/pipeline.md 里具体的职位链接(posting 级),两者互补,不能互相替代。
  • 本工具只读、不修改任何文件:pipeline 的清理是按上面的判定手工/由 agent 写入 data/pipeline.md 的,check-liveness.mjs 本身不碰数据文件。

sweep 之后,"Pending" 区剩下的就是活着的职位链接,可以按 modes/pipeline.md 的 Workflow 继续逐条处理;失效链接已经以 posting expired (liveness sweep) 的留痕形式归档在 "Processed" 区,随时可以回查为什么某个职位没有被评估。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
898
5.82 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
921
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.8 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
391