2025 年 8 月,我用 Firecrawl 把公开 JD 打成了可反复追问的薪酬技能卡
八月初定盘 2026 人才需求,业务 leader 直接问我:市场到底在抢什么人,薪水水位到哪一步了。我手里只有去年 Q4 的猎头口头数据,太旧也太散。决定自己动手,用 Firecrawl 把公开信息先打成能追问的形态。
为什么选 Firecrawl
之前也试过 Perplexity 零散问市场、自己写 playwright 爬,但前者每次都要重新喂上下文,后者一有反爬就得修脚本。Firecrawl 当时主推结构化提取,能直接给 schema 出 json,还能顺手吐 markdown 做 fallback。我的打算是:career page 进来,出来的是 title、location、salary_raw、must_skills 这些字段。
第一天跑通本地流程
注册拿 key 后,先拿一家友商的 careers 页试。
export FC_API_KEY=fc-xxx
curl -X POST https://api.firecrawl.dev/v1/scrape \
-H "Authorization: Bearer $FC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://careers.example.com/open-roles",
"formats": ["markdown", "json"],
"jsonOptions": {
"schema": {
"type": "object",
"properties": {
"roles": {
"type": "array",
"items": {
"type": "object",
"properties": {
"title": {"type": "string"},
"location": {"type": "string"},
"salary": {"type": "string"},
"requirements": {"type": "string"}
}
}
}
}
}
}
}'
返回的 json 里 salary 基本是“面议”“15-25k*14”“年包 30-45 万”混在一起。我又写了个 30 行 node 脚本,用正则加简单 LLM 归一到 monthly_base 和 total_first_year 两列,存成带抓取日期的 jsonl。
真正开始干活
我挑了 6 家目标公司外加 3 个主流招聘平台公开列表。策略是每周三晚上跑增量,只抓“最近 30 天更新或新增”的链接,存本地。后面再用 sqlite + 简单 embedding 做“这个岗位和我们 JD 的技能重合度”小查询。
三个真坑
第一个是反爬与等待。有一家核心竞品职位页是重度 React 渲染,默认 30 秒超时抓不到内容。后来加了 waitFor: 8000 和备用 proxy 才把成功率拉到 85% 以上。第一次全量跑漏了将近一半。
第二个是字段漂移。同样是要求,一家写 must_have_skills,一家写 qualifications,还有一家直接塞在 description 里。schema 得跑三轮才能收敛,建议先抓 markdown 全文,再让模型按固定模板重构一次。
第三个是成本失控。第一次贪多,一周抓 180 个页面,账单直接 120 刀。后面改成只保留 4 个最核心来源,其余用 Perplexity 做抽样验证,月成本降到 25 刀左右,还加了本地文件缓存避免重复抓。
真正用起来的那周
把这些卡片喂给团队周例会后,效果最明显的一次是问“市场对带 LLM 工程化经验的人到底溢价多少”。我当场拉出 17 条相关 JD 的薪酬分布和技能关键词频率,而不是凭感觉说“好像高 30%”。业务 leader 第一次觉得数据不是黑箱。
复盘
Firecrawl 解决的是从网页到结构化的脏活,但 HR 真正缺的从来不是更多数据,而是“这些数据在当前业务上下文里到底意味着什么”。我现在每周只维护 4 个来源,其余全靠抽样 + 人工判断。工具省的是体力,不是判断力。把公开数据和自己对团队真实需求的理解掰扯清楚,这事才算做成了。