自动化求职工具:通过 Boss直聘 搜索岗位并将结果每日保存到 Obsidian。当用户想找工作、设置求职提醒、抓取 Boss直聘 职位数据时触发。用户提到"找工作"、"求职"、"Boss直聘"、"每天推送职位"等关键词时立即使用此 skill。
帮用户在 Boss直聘 搜索目标岗位,每日自动抓取结果并保存到 Obsidian。
反爬绕过策略:不伪造 HTTP 请求,而是用 DrissionPage 控制用户本机真实 Chrome 浏览器,让浏览器以用户身份发出请求,再用网络包监听拦截 Boss直聘 内部 API(/wapi/zpgeek/search/joblist.json)响应的 JSON 数据。对服务器来说和用户手操无区别。
薪资字段:Boss直聘 在 DOM 层用私用区 Unicode 字符做字体混淆反爬,但 API 响应的 JSON 里 salaryDesc 字段是明文(如 "25-40K·13薪"),所以必须用 API 拦截而非 DOM 爬取。
首次登录:需用户扫一次 QR 码,之后 Chrome profile 保存 cookie,后续全自动。
在做任何部署之前,先用 AskUserQuestion 收集以下信息:
目标岗位关键词(多选或自填)
Base 城市
薪资下限过滤(月薪上限低于此值的岗位不显示)
目标公司偏好(可多选)
收集完信息后,执行以下步骤:
python3 -c "import DrissionPage" 2>/dev/null || pip3 install DrissionPage pyyaml -q
cat ~/Library/Application\ Support/obsidian/obsidian.json | python3 -c "
import json,sys
d=json.load(sys.stdin)
for v in d.get('vaults',{}).values():
print(v['path'])
"
选择用户的主 vault,在 3. Resources(或 Resources)下创建 求职/<城市><岗位> 子目录。
根据用户的回答生成配置,城市代码映射:
深圳: 101280600 | 北京: 101010100 | 上海: 101020100
广州: 101280100 | 杭州: 101210100 | 成都: 101270100
公司规模偏好处理:
10000人以上 的岗位天使轮/A轮 的岗位company_blacklist 字段核心逻辑(不要修改,这是经过验证的可工作版本):
# 登录检测
page.get("https://www.zhipin.com/")
time.sleep(3)
if not (page.ele(".nav-figure", timeout=3) or page.ele(".user-nav", timeout=1)):
# 跳转登录页,等用户扫码,最多 300 秒
page.get("https://www.zhipin.com/web/user/?ka=header-login")
for i in range(300):
time.sleep(1)
if "zhipin.com" in page.url and "login" not in page.url and "user" not in page.url:
break
# API 拦截抓取(每个关键词每页)
page.listen.start("zpgeek/search/joblist.json")
page.get(f"https://www.zhipin.com/web/geek/jobs?query={keyword}&city={city_code}&page={page_num}")
resp = page.listen.wait(timeout=12)
page.listen.stop()
job_list = resp.response.body["zpData"]["jobList"] # 真实 JSON 数据
# 关键字段
# item["salaryDesc"] → "25-40K·13薪"(明文,无混淆)
# item["jobName"] → 职位名
# item["brandName"] → 公司名
# item["jobExperience"] → "3-5年"
# item["jobDegree"] → "本科"
# item["brandStageName"] → "A轮"
# item["brandScaleName"] → "100-499人"
# item["areaDistrict"] → "南山区"
# item["encryptJobId"] → 用于构造链接 https://www.zhipin.com/job_detail/{id}.html
# {城市} {关键词} 职位 · YYYY-MM-DD
> 共 N 条(月薪上限 ≥ XK)
| 职位 | 公司 | 薪资 | 经验 | 规模/阶段 | 区域 | 链接 |
|------|------|------|------|-----------|------|------|
| ... | 🏢字节跳动 | 25-50K·15薪 | 3-5年·本科 | 10000+/D轮 | 南山区 | [查看](...) |
大厂岗位(brandScaleName 含 10000)在公司名前加 🏢 标注。
# 读取用户配置的运行时间,默认 08:30 工作日
(crontab -l 2>/dev/null | grep -v "job-hunter"; \
echo "30 8 * * 1-5 cd $HOME/job-hunter && python3 scraper.py >> $HOME/job-hunter/run.log 2>&1") \
| crontab -
Q: 抓到的条数少(< 20条)
→ 每个关键词默认只取前2页(30条),去重后会减少。可增加 pages_per_keyword 或增加关键词。
Q: 薪资显示为 -K
→ 说明用了 DOM 爬取而非 API 拦截。确认使用 page.listen.start("zpgeek/search/joblist.json") 方式。
Q: 登录失效
→ 删除 ~/.job-hunter-chrome/Default/Cookies,重新扫码。
Q: 想加岗位描述(JD)
→ 需对每条岗位额外请求详情页 API,时间成本 ×5,按需开启。详情页 API:/wapi/zpgeek/job/card.json?jobId={encryptJobId}
Q: 想换平台(拉勾网等)
→ 拉勾网同样无公开 API,但可用类似的 API 拦截方式,其搜索接口为 /api/search/positions。