ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

用 Bun 打造零依赖、全球通用的职位搜索 CLI:ai-job-search 仓库 LinkedIn Search Skill 实战指南

用 Bun 打造零依赖、全球通用的职位搜索 CLI:ai-job-search 仓库 LinkedIn Search Skill 实战指南 AI 应用AI 技能【免费下载链接】ai-job-searchThe job search that runs on your machine. AI job application framework built on Claude Code: evaluate postings, tailor CVs, write cover letters, prep interviews. Fork it and own it.项目地址https://gitcode.com/GitHub_Trending/ai/ai-job-search点击查看免费下载本指南围绕 ai-job-search 仓库中的 linkedin-search Skill 展开系统讲解如何通过一条bun run命令在任意国家/城市/远程市场实时检索 LinkedIn 公开职位、按时间与工作形态过滤并抓取单个职位的完整描述。读完本文你将掌握这套 CLI 的完整命令与参数用法、底层jobs-guest端点调用机制、防御式参数校验与退避重试的实现细节以及如何把它作为仓库「job-portal-skill」模式的可复用样板接入自己的求职流程。一、Skill 定位为「Fork 后自用」设计的国家无关职位搜索在 ai-job-search 仓库中.agents目录下维护着一组彼此独立的职位门户 Skill如 freehire-search、jobbank-search、jobindex-search 等linkedin-search是其中覆盖范围最广的一个它依托 LinkedIn 全球统一的jobs-guest公开端点不需要账号、不需要 API Key、零运行时依赖只要机器上有bun就能跑。该 Skill 的核心设计哲学在 SKILL.md 中写得很明确位置永远由用户显式传入--location因此同一个 Skill 对任何国家的求职者开箱即用——你在孟买搜数据工程师和在柏林搜产品经理用的都是同一份代码变的只是--location字符串。这正是仓库「job-portal-skill 模式」的一个国家无关country-agnostic范例。⚠️仅限个人使用该工具读取的是 LinkedIn 的公开职位页面自动化访问违反 LinkedIn 服务条款ToS。请保持低访问量禁止商业化或批量采集用途风险自负。这一提示同时存在于 SKILL.md 与 cli/README.md 中。二、工作原理jobs-guest公开端点与纯 HTML 解析整个 CLI 只依赖两个无鉴权的公开端点见 url-reference.md 与 helpers.ts 中的常量定义端点用途https://www.linkedin.com/jobs-guest/jobs/api/seeMoreJobPostings/search职位搜索返回职位卡片 HTML 列表https://www.linkedin.com/jobs-guest/jobs/api/jobPosting/jobId单个职位详情返回完整 HTML搜索端点参数search命令发出的请求本质上是把 CLI 参数翻译成下列查询参数见 search.ts 的buildUrl实现URL 参数含义示例keywords关键词职位名/技能/角色data engineerlocation地点字符串Mumbai, Maharashtra, India·Berlin, Germany·Remotef_TPR发布时间窗口秒r6048007 天、r259200030 天f_WT工作形态1现场办公 ·2远程 ·3混合start分页偏移每页 10 条0、10、20…其中f_TPR的秒数换算由 helpers.ts 完成--jobage 7→r6048007×86400 秒--jobage-minutes 30→r180030×60 秒f_WT则由workTypeFlag()映射remote→2、hybrid→3、onsite→1。响应解析策略两个端点返回的都是 HTML 而非 JSON。搜索响应是一个扁平的li职位卡片列表parseJobCards() 以data-entity-urnurn:li:jobPosting:id为切分点把 HTML 切成多个独立块逐块独立解析——这样即使某张卡片畸形也不会拖垮其余结果。每张卡片提取职位 ID、标题base-search-card__title回退到sr-onlyspan、公司base-search-card__subtitle、地点job-search-card__location、发布日期job-search-card__listdate的datetime属性与完整链接。详情页解析在 parseJobDetail() 中实现标题来自top-card-layout__title公司来自topcard__org-name-link地点来自topcard__flavor--bullet富文本描述取自show-more-less-html__markup回退到description__text并把br、/p等标签转换为换行以保留段落结构。seniority、employment type、job function、industries 四项「职位标准」job criteria通过正则成对抓取description__job-criteria-subheader标签与紧随其后的description__job-criteria-text值。三、运行前提只有bun没有别的依赖该 Skill 的 CLI 位于.agents/skills/linkedin-search/cli/其 package.json 中dependencies为空对象devDependencies只有 TypeScript 类型定义typescript与types/bun注释也明确写着「bun install可选仅安装开发期类型」。因此cd .agents/skills/linkedin-search/cli bun install # 可选只安装 TypeScript 开发类型不安装任何依赖也能直接运行示例命令均以仓库根目录为工作目录bun run .agents/skills/linkedin-search/cli/src/cli.ts --helpCLI 的入口 cli.ts 顶部声明了#!/usr/bin/env bunpackage.json也注册了linkedin-searchbin 名方便在安装后以bunx linkedin-search方式调用。运行测试使用bun test --timeout 30000类型检查使用tsc --noEmit。四、命令一search —— 多条件职位搜索命令格式与全部参数bun run .agents/skills/linkedin-search/cli/src/cli.ts search --location place [flags]完整参数表与 SKILL.md 保持一致并补充取值范围参数别名说明--location text-l必填。LinkedIn 地点字符串如Mumbai, Maharashtra, India、Berlin, Germany、London, United Kingdom或Remote--query text-q关键词搜索职位名/技能/角色推荐使用--jobage days—最近 N 天内发布1、7、14、30缺省返回全部--jobage-minutes n—最近 N 分钟内发布亚天级精度如30。与--jobage冲突二者只能传一个--remote mode—工作形态过滤remote、hybrid、onsite--page n—页码从 1 起每页 10 条结果--limit n-n客户端侧截断限制最终输出的结果条数--format fmt—json默认tableplain官方示例可直接复制运行# 班加罗尔的数据工程师最近 30 天 bun run .agents/skills/linkedin-search/cli/src/cli.ts search -q data engineer -l Bengaluru, Karnataka, India --jobage 30 --format table # 柏林的产品经理远程 bun run .agents/skills/linkedin-search/cli/src/cli.ts search -q product manager -l Berlin, Germany --remote remote --format table # 任意岗位全远程 bun run .agents/skills/linkedin-search/cli/src/cli.ts search -q paralegal -l Remote --format table # 工程师岗远程最近 30 分钟发布 bun run .agents/skills/linkedin-search/cli/src/cli.ts search -q engineer -l Remote --jobage-minutes 30 --format table从源码看--limit 0是合法取值测试 search.test.ts 专门验证了「--limit 0输出零条结果」可用于只探测接口而不真正输出结果分页偏移由start (page - 1) * 10计算所以--page 2对应偏移 10即第 1120 条。五、命令二detail —— 抓取单个职位完整详情命令格式bun run .agents/skills/linkedin-search/cli/src/cli.ts detail id|url [--format json|plain]id是search结果中的数字职位 ID如4426311357也可以传入完整 LinkedInjobs/view/...URL 或urn:li:jobPosting:...URN。返回内容包括完整职位描述、资深级别seniority、雇佣类型employment type、职位职能job function与所属行业industries外加职位状态ACTIVE/CLOSED / EXPIRED。# 查看某个职位完整信息纯文本格式适合人读 bun run .agents/skills/linkedin-search/cli/src/cli.ts detail 4426311357 --format plain输入的归一化与安全防线detail命令对输入做了严格校验这是本 Skill 最值得借鉴的防御式设计之一。入口 detail.ts 的normalizeId()依次尝试URNurn:li:jobPosting:数字→ 提取数字 ID裸数字6 位以上的纯数字直接视为 IDURL通过真实 URL 解析而非字符串截取验证主机名必须是linkedin.com及其子域再从/jobs/view/id路径提取数字 IDlinkedin.com.evil.io这类仿冒主机和linkedin.comevil.io这类 userinfo 欺骗都会被拒绝无协议的 slug如software-engineer-1234567890取末尾数字。非 LinkedIn 域名的 URL 一律拒绝BAD_ID退出码 1。这一点有明确的事故背景早期实现会把任意 URL 的第一个 6 位以上路径段当成职位 ID导致用户从职位页复制的 Greenhouse、Lever 投递链接被错误地抓取成一个毫不相干的 LinkedIn 职位并正常退出。回归测试 detail-input.test.ts 同时覆盖了「外部招聘板 URL 被拒且不发任何请求」和「LinkedIn URL 正确提取 ID 并拼出请求地址」两条路径。六、输出格式与错误契约格式适用场景json默认。程序化使用把结果 ID 传给detail做二次查询table快速人工浏览标题/公司/地点/日期对齐列plain阅读单个职位详情detail命令table格式由 search.ts 的renderTable()生成列宽固定ID 11、标题 42、公司 26、地点 24空结果显示No results.json格式包一层{ meta: { count, page }, results: [...] }元信息。错误契约所有错误一律写入stderr格式为 JSON{ error: ..., code: ... }进程退出码为1。这意味着你可以放心地用2err.json捕获结构化错误而不用解析人读文本。目前 CLI 中出现的错误码包括错误码触发条件NO_LOCATIONsearch缺省--locationUNKNOWN_FLAG传入了该命令不认识的参数CONFLICTING_AGE_FLAGS同时传--jobage与--jobage-minutesBAD_ARG数字参数不是 ≥1 的整数BAD_IDdetail输入无法解析出 LinkedIn 职位 ID含外部域名NO_IDdetail缺少id\|url参数NOT_FOUND职位页面返回 404SEARCH_FAILED/DETAIL_FAILED请求/解析过程异常BAD_CMD/INTERNAL_ERROR未知子命令 / 未捕获异常七、源码级纵深参数校验与防「静默丢过滤」search的每个数字参数都经过 cli.ts 中parseIntFlag()的严格校验这里藏着两个非常值得学习的工程细节其一用Number()而非parseInt()。注释直接点明了事故原因parseInt(0.5)会截断成0而jobage 0会让jobageToTPR()返回null结果是f_TPR参数被静默地从请求里丢弃、CLI 却以 0 退出——用户以为加了「最近 N 天」过滤实际拿到的是全量结果。因此parseIntFlag()要求必须是 ≥1 的整数小数如1.5与非数字如foo一律报BAD_ARG。对应测试见 cli-flag-validation.test.ts 的「fractional exits 1 with BAD_ARG instead of truncating」系列。其二未知参数直接拒绝而不是忽略。cli.ts 在分发命令前用KNOWN_FLAGS白名单逐一核对任何多余参数立即输出UNKNOWN_FLAG错误并退出 1。注释里记录的教训是拼错参数名曾让某个门户 CLI 把整个数据库13,862 条结果当作匹配查询输出。测试 cli-flag-validation.test.ts 验证了「bogus flag 必须退出 1 且 stdout 为空」。其三互斥校验--jobage与--jobage-minutes同时出现时输出CONFLICTING_AGE_FLAGS二者都在设置发布时间窗口语义重叠。八、源码级纵深请求、退避重试与超时所有 HTTP 请求都经由 helpers.ts 的htmlFetch()它实现了完整的稳健性策略重试与指数退避最多 6 次重试共 7 次尝试遇到429限流或5xx服务端错误时从 500ms 起退避每轮翻倍、封顶 8 秒并附加最多 500ms 的随机抖动jitter避免雪崩式同时重试404 特殊处理返回空字符串由调用方判定「职位不存在」而非报错——注意 404 不重试超时控制每次请求 15 秒超时AbortSignal.timeout(15000)请求头携带User-Agent: Mozilla/5.0 (compatible; linkedin-search-cli/1.0)、标准 Accept 头与X-Requested-With: XMLHttpRequest模拟前端 AJAX 请求形态。退避行为被 retry-backoff.test.ts 用离线 stub 钉死429 后第二次请求成功共 2 次调用、404 只请求 1 次不重试、持续 500 时「初始请求 6 次重试」共 7 次后抛错。解析层的两个细节也值得一提extractDivContent()通过追踪div嵌套深度正确截取指定 class 的 div 内容规避node-html-parser在 LinkedIn 卡片上的已知嵌套解析 bugdecodeHtmlEntities()用String.fromCodePoint而非fromCharCode正确解码 emoji 等补充平面 Unicode 字符并支持十进制/十六进制数字实体。此外parseJobDetail()对「职位已关闭」的检测做了作用域限定只在描述区之前的 topcard 区域匹配closed-job__flavor或No longer accepting applications标记防止招聘方描述正文里的引用话术误报 CLOSED同时注释谨慎地说明「无标记 ≠ 职位一定开放」isActive: true仅表示「未发现关闭横幅」。九、测试验证与质量保障该 Skill 的 CLI 测试集中在cli/tests/全部基于bun:test离线运行stubfetch不触网覆盖search.test.ts--limit 0输出空结果、--jobage-minutes 30正确构造f_TPRr1800cli-flag-validation.test.ts数字参数校验、互斥校验、未知参数拒绝、NO_LOCATION等完整错误契约detail-input.test.ts外部招聘板 URL 在发请求前被拒BAD_ID、LinkedIn URL 正确归一化retry-backoff.test.ts429/5xx 退避重试、404 不重试、重试次数上限parsing.test.ts 与 helpers.ts卡片/详情解析与辅助函数的行为回归。运行方式在cli/目录内bun test --timeout 30000。十、在 ai-job-search 求职流程中的用法与合规边界作为仓库「job-portal-skill 模式」的一员linkedin-search的典型用法是先用search以json格式拿到职位 ID 列表再把 ID 逐个传给detail获取完整描述——这两步输出都极易被 Claude Code 等 Agent 解析、用于评估职位与撰写求职材料呼应项目定位「evaluate postings, tailor CVs, write cover letters, prep interviews」。若要对比其他门户可参阅同模式的 freehire-search、jobbank-search、jobindex-search、jobdanmark-search、jobnet-search 等 Skill它们共享「零依赖 Bun CLI 公开端点 参数校验 退避重试」的架构骨架。使用边界需要牢记个人使用、低访问量、禁止商业化与批量采集LinkedIn ToSdetail的输入归一化已挡住外部域名但所有请求最终仍落在 LinkedIn 公开端点上请对退避重试与并发节奏保持克制。数据形态上搜索每页固定 10 条、页码从 1 起、职位 ID 为纯数字如4426311357原样传给detail——这些约定决定了下游脚本的边界条件。赞分享AI 应用AI 技能【免费下载链接】ai-job-searchThe job search that runs on your machine. AI job application framework built on Claude Code: evaluate postings, tailor CVs, write cover letters, prep interviews. Fork it and own it.项目地址https://gitcode.com/GitHub_Trending/ai/ai-job-search点击查看免费下载相关推荐Higress hmac-auth 插件完全指南基于 HMAC 的请求签名认证与鉴权实战Higress hmac auth 插件完全指南基于 HMAC 的请求签名认证与鉴权实战 hmac auth 是 HigressAI Native APIAI 应用AI 技能k-skill daangn-jobs-search 技能全解析基于 Remix _data 路由的 당근알바 只读职位搜索实战k skill daangn jobs search 技能全解析基于 Remix _data 路由的 당근알바 只读职位搜索实战 k skill 是一个面向韩人工智能AI 技能k-skill daangn-realty-search零依赖 Python 解析当根房产 RELAY_STORE 的房源检索实战指南k skill daangn realty search零依赖 Python 解析当根房产 RELAY_STORE 的房源检索实战指南 本篇围绕 k skil人工智能AI 技能上一篇终极Docker-Mailserver存储管理指南快照与克隆技术完整应用方案下一篇ClawX 的 ACP 文件活动机制OpenClaw 工具调用到工作区预览的安全投影与实操解析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表