用 jobindex-cli 在丹麦 Jobindex.dk 上检索职位:一条命令完成搜索、详情抓取与 JSON 结构化输出

📅 发布时间:2026/9/30 6:54:07
用 jobindex-cli 在丹麦 Jobindex.dk 上检索职位:一条命令完成搜索、详情抓取与 JSON 结构化输出
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点击查看免费下载Jobindex.dk 是丹麦最大的在线职位门户之一覆盖 IT、工程、设计、营销等全行业实时职位。本项目内置的jobindex-cli位于 .agents/skills/jobindex-search/cli/是一个免认证、基于 Bun 的 TypeScript 命令行工具它内部解析 Jobindex 返回的 HTML 与内嵌数据对外统一输出干净的 JSON、表格或纯文本并配套search/detail两条子命令形成搜索 → 取详情的完整工作流。读完本文你将掌握该 CLI 的全部命令参数、响应字段语义、底层解析与重试机制并能把它接入 AI 求职自动化流程中。概览设计定位与数据流从 CLI 文档 可以概括出该工具的三个核心事实Base URLhttps://www.jobindex.dk/认证无Jobindex 的公开搜索与职位详情页无需任何凭据数据格式Jobindex 的接口返回 JSON 与内嵌 HTML 的混合体jobindex-cli在内部解析 HTML 片段向调用方输出结构化数据这套设计让它非常适合脚本化集成既可以直接在终端里检索也可以被 AI Agent 通过 .agents/skills/jobindex-search/SKILL.md 的触发规则Bash(bun run .agents/skills/jobindex-search/cli/src/cli.ts *)调用用于评估丹麦职位、筛选岗位后进入简历定制与求职信撰写环节。安装两条命令跑起来CLI 以 Bun 运行时开发package.json 声明了bunli/core、zod、node-html-parser等依赖且type: module安装方式见 CLI 文档cd skills/jobindex-search/cli bun install从 package.json 可以看到项目还提供了便利入口bun start等价于bun run src/cli.ts并声明了jobindex作为 bin 名称bun link后可直接使用jobindex命令bun test运行测试套件超时 30 秒bun run typecheck执行tsc --noEmit。命令总览与全局约定CLI 提供两条子命令入口文件为 .agents/skills/jobindex-search/cli/src/cli.ts命令作用search按关键词搜索职位列表detail抓取单个职位的完整详情所有命令都接受--format json|table|plain默认jsondetail仅支持json|plain。所有错误统一写入stderr格式为{ error: ..., code: ... }进程以退出码1结束。值得注意 cli.ts 的未知 flag 拒绝机制命令分发前CLI 会逐 token 校验--long与-short两种形式。源码注释记录了动机——被静默丢弃的过滤参数会改变搜索结果而不报任何错误曾经一个拼错的 flag 名导致整个门户数据库被当作匹配结果返回。因此任何未声明的 flag包括未注册的短 flag、负数形式的取值都会触发{ error: unknown flag ... - flags are never silently ignored ..., code: UNKNOWN_FLAG }并以退出码1结束防止产生误导性的全量返回结果。search搜索职位列表端点与调用方式文档记录的端点为GET https://www.jobindex.dk/jobsoegning.json从 search.ts 源码看实际请求的是${BASE_URL}/jobsoegning?${params}。两者并不矛盾Jobindex 曾以jobsoegning.json提供结果但随后改为客户端渲染——helpers.ts 的注释明确说明该 JSON 端点如今返回204 No Content完整结果内嵌在 HTML 页面var Stash {...}脚本块中路径jobsearch/result_app - storeData - searchResponse - { hitcount, results[] }。CLI 通过extractStash扫描大括号深度并兼顾字符串转义地截取该 blob再由findSearchResponse递归定位结果对象。bun run src/cli.ts search [flags]Flags 一览Flag类型默认值说明--query/-qstring—关键词搜索如python、grafisk designer必需--pagenumber1页码1 起始--jobagenumber9999职位发布最大天数1、7、14、30或9999全部--sortstringscore排序score相关度或date最新优先--limitnumber—客户端侧截断返回结果总数--formatstringjson输出格式json、table、plain参数在源码层由 search.ts 的 zod 模式约束page必须是1的整数z.coerce.number().int().min(1).default(1)jobage同样1limit为可选整数format为枚举。数值参数先coerce再校验传入--page not-a-number会得到validation类错误见 cli-contract.test.ts。查询参数按q、page、jobage、sort拼装进 URLURLSearchParams自动编码空格/中文/丹麦语字符无需手动处理。--query缺失时立即报MISSING_REQUIRED并退出search.ts。排序与时效选项Sort options值说明score相关度 / 最佳匹配默认date最新发布优先Jobage options值说明1仅今天发布7最近 7 天14最近 14 天30最近 30 天9999全部时间默认典型用法示例# 搜索最近 7 天发布的 Python 职位按日期排序 bun run src/cli.ts search --query python --jobage 7 --sort date # 搜索 grafisk designer 职位仅显示前 5 条 bun run src/cli.ts search --query grafisk designer --limit 5 # data engineer 第 2 页表格输出 bun run src/cli.ts search --query data engineer --page 2 --format table响应结构JSON 格式{ meta: { total: 237, page: 1, perPage: 20 }, results: [ { id: h1647303, title: Data Engineer til opbygning af Gavefabrikkens dataplatform, company: Gavefabrikken, companyUrl: https://www.gavefabrikken.dk/, location: Valby, date: 2026-03-12, url: https://www.jobindex.dk/jobannonce/h1647303/data-engineer-til-opbygning-af-gavefabrikkens-dataplatform, description: Vi søger en dygtig Data Engineer til at opbygge og vedligeholde vores dataplatform... } ] }字段说明id— 以h前缀开头的字符串 ID如h1647303请原样传给detail命令。company— 公司名部分聚合型列表可能为null。companyUrl— 公司主页 URL不存在时为null。location— 城市或区域未列出时为null。date—time元素datetime属性的 ISO 日期YYYY-MM-DD可能为null。description— 职位卡片内的简介摘录可能为null或空。url— 该职位的完整 Jobindex.dk URL。meta.total— 从hitcount解析Jobindex 内部使用丹麦式千分位点号如18.903CLI 会剥离.后转为整数18903。从源码看search 结果字段实际来自 Stash blob 的results[]id取r.tidtitle取r.headline公司取r.company?.name ?? r.companytext位置优先r.area、回退到r.geojson.features[0].properties.title日期取r.firstdate并额外提取apply_deadline/lastdate得到deadlineapply_deadline_asap为真时 deadline 强制为null表示尽快申请、无固定截止日。perPage固定为20这是 Jobindex 的分页硬限制CLI 不提供--per-page参数。关于区域过滤的重要提示Jobindex API 并不可靠地支持通过查询参数做地区/区域过滤。area与geoareaid参数会被静默忽略。若要按地点筛选请在--query中加入城市名如--query python aarhus或使用--limit截断后对 JSON 输出做外部过滤。SKILL 文档给出了同款建议例如--query data engineer københavn、--query python aarhus。若要系统化地按地域浏览.agents/skills/jobindex-search/url-reference.md 还提供了可直接构造的 URL 形态如/jobsoegning/storkoebenhavn?q...、/jobsoegning/it/itdrift/storkoebenhavn?qdataengineer以及仅能通过 UI 面板筛选的雇佣类型、工时、远程工作等条件——这些无法通过本 CLI 的查询参数表达可作为人工复核阶段的补充手段。输出格式与底层解析--format的行为在 search.ts 中实现jsonJSON.stringify(output, null, 2)美化输出到 stdout便于程序化处理与管道传递table固定列宽对齐id 11 字符、title 40 字符截断、company 20 字符截断适合快速扫读plain逐字段id:/title:/company:/location:/date:/deadline:/url:/description:分行输出。历史上的解析路径README 保留的Parsing notes基于对result_list_box_html的正则提取每个职位卡片包裹在[data-beacon-tid]/div#jobad-wrapper-id内字段选择器为h4 a标题与链接、.jix-toolbar-top__company a公司与公司链接、span.jix_robotjob--area地点、time[datetime]日期、首个p描述卡片分div.PaidJob赞助与div.jix_robotjob聚合两种类型选择器一致。该逻辑至今保留在 helpers.ts 的 parseJobCards 中注释指出 node-html-parser 对这类含未闭合标签的 HTML 存在嵌套解析 bug正则方案反而更可靠而现行实现则优先走 Stash JSON 路径。detail抓取单个职位完整详情URLhttps://www.jobindex.dk/jobannonce/{id}/{slug}bun run src/cli.ts detail id [--format json|plain]id即search结果中的职位 ID如h1647303。slug 是可选的——CLI 会先构造https://www.jobindex.dk/jobannonce/{id}并跟随重定向得到规范 URL也可以直接把search返回的完整url传进来。你也可以把完整 URL 直接作为id参数传入。FlagsFlag类型默认值说明--formatstringjson输出格式json、plain示例# 使用 search 结果中的 ID bun run src/cli.ts detail h1647303 # 使用完整 URL bun run src/cli.ts detail https://www.jobindex.dk/jobannonce/h1647303/data-engineer-til-opbygning-af-gavefabrikkens-dataplatform # 纯文本输出 bun run src/cli.ts detail h1647303 --format plain响应结构JSON 格式{ id: h1647303, title: Data Engineer til opbygning af Gavefabrikkens dataplatform, company: Gavefabrikken, companyUrl: https://www.gavefabrikken.dk/, location: Valby, København, date: 2026-03-12, deadline: 2026-04-01, employmentType: Fastansættelse, hours: Fuldtid, applyUrl: https://www.gavefabrikken.dk/jobs/apply/123, url: https://www.jobindex.dk/jobannonce/h1647303/data-engineer-til-opbygning-af-gavefabrikkens-dataplatform, description: Full job description text here... }两种页面形态与字段差异Jobindex 的详情页有两种形态字段可用性不同jobindex 原生页可通过其jd-*事实块识别如jd-deadline、jd-location、jd-type、jd-workhours携带公司、地点、ISO 截止日期、雇佣类型与工时外部 ATS 透传页即雇主在自己托管系统如 hr-manager/Talentech上的广告经 jobindex 转发页面上没有可靠的公司锚点——此时company为null而不是填成 ATS 品牌名地点与截止日期若有则取自广告自身的部件。字段说明id/url— 始终是 jobindex 的 ID 及其jobannonceURL绝不使用页面的og:url/canonical透传页上这些指向外部 ATS而非职位本身deadline—YYYY-MM-DD或null丹麦语长日期如13. september 2026与部件里的DD-MM-YYYY都会被转换employmentType/hours— 取自原生事实块透传页上为nullcompanyUrl— 当前恒为null两种页面形态都没有可用的公司链接applyUrl— 存在时为 Jobindex 的跳转链接/c?t...否则为nulldescription— 广告正文纯文本HTML 已剥离正文为空时回退到页面的 meta description除id、title、url外所有字段都可能为null。URL 规范化安全边界detail.ts 的 buildUrl 是存下来的不可信URL → 网络请求之间的闸门URL 输入必须满足 host 为jobindex.dk或其子域、路径匹配/jobannonce/idid 形如[a-zA-Z]\d兼容h1647303、r13677312等随后用提取出的 ID 重建https://www.jobindex.dk/jobannonce/{id}短链——即裸 ID 路径一直使用的规范形态。裸 ID 则保持宽松的字母数字下划线横线 token 约束未知 ID 由服务端 404 兜底。源码注释记录了一次真实事故旧版会原样抓取任意 http(s) URL导致重定向目标、仿冒域名或首页被解析成格式良好的虚假职位并以退出码 0 返回这个漏洞正是该严格校验的由来。任何无法解析的输入都会得到BAD_ID错误。细节工程日期归一化与 HTML 实体解码丹麦语页面给日期解析带来不少坑detail.ts 的 toIsoDate 与 helpers.ts 的 decodeHtmlEntities 专门处理了三类形态ISOYYYY-MM-DD直接保留部件格式DD-MM-YYYYhr-manager 部件常见翻转为YYYY-MM-DD丹麦语长格式13. september 2026借助内置的 12 个月丹麦语映射表januar→01 … december→12转换。实体解码覆盖amp;、lt;、gt;、quot;、#39;、apos;以及丹麦语特有的oslash;→ø、aelig;→æ、aring;→å含大写再加上十进制#233;与十六进制#xE9;数字实体。数字实体解码使用String.fromCodePoint而非fromCharCode确保补充平面码点如 emoji U1F600正确解码、越界值直接丢弃——parsing.test.ts 中有对应回归用例如#xF8;→ø、#128512;→。描述正文的提取还会先剔除head、script、style与注释避免文本扫描读到 CSS/JS广告正文为空或过短时回退到og:description或descriptionmeta。错误处理契约所有错误统一写入stderrJSON 格式进程退出码1{ error: Job not found, code: NOT_FOUND } { error: API request failed: 500 Internal Server Error, code: API_ERROR } { error: Failed to parse job listing HTML, code: PARSE_ERROR } { error: --query is required, code: MISSING_REQUIRED }这个契约被测试显式锁定cli-contract.test.ts 断言无 query 的 search与无 ID 的 detail都以退出码 1、stdout 为空、stderr 为上述 JSON 结构结束非法数字参数则产出{ ok: false, error: { kind: validation, option: page, ... } }。stdout 永远只承载正常结果这让管道处理如... | jq不会被错误信息污染。请求健壮性超时、重试与退避helpers.ts 的 htmlFetch以及对称的apiFetch内置了稳健的请求策略这是把 CLI 用于自动化时的关键保障超时每次请求AbortSignal.timeout(15000)15 秒无响应即中止重试最多 6 次遇到429限流或5xx时指数退避重试——初始延迟 500ms每次翻倍上限 5000ms并叠加 0–500ms 随机抖动jitter避免惊群UA 与语言携带Mozilla/5.0 (compatible; jobindex-cli/1.0)UA 与Accept-Language: da,en;q0.9redirect: follow自动跟随404detail场景下 404 被翻译为明确的Job not found。重试耗尽后抛出API request failed: status statusText最终以API_ERROR呈现。实战工作流把 CLI 接入求职自动化结合 SKILL.md 的使用建议推荐模式是search→detail两步走用search按关键词、时效、排序定位职位拿到id列表对候选职位逐个detail id取完整描述、截止日期、雇佣类型、工时与投递链接供后续的简历定制、求职信撰写与面试准备环节消费。高频技巧--jobage 7或--jobage 1只看新鲜职位不带则含全部历史--sort date看最新发布--format table快速扫读、--format json交给程序处理、--format plain通读单条详情跨页浏览用--page每页固定 20 条单页内截断用--limit。值得留意的两个已知限制均为 Jobindex 侧行为而非 CLI 缺陷分页大小固定 20、不可配置区域过滤参数不生效按城市筛选必须在 query 里带城市名。这两个约束在 README 与 SKILL.md 中被反复强调写自动化脚本时务必遵守。最后本仓库还内置了面向其他门户的同构 CLIfreehire、jobbank、jobdanmark、jobnet、linkedin-search均位于 .agents/skills/它们共享相同的JSON 错误契约 未知 flag 拒绝 重试退避设计掌握了jobindex-cli的用法即可快速迁移到其余求职数据源上。赞分享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 项目实战jobbank-cli 详解——基于 RSS 与 JSON-LD 的丹麦高端职位检索工具ai job search 项目实战jobbank cli 详解——基于 RSS 与 JSON LD 的丹麦高端职位检索工具 本篇文章围绕 ai job seAI 应用AI 技能ai-job-search 实战用 jobbank-search 技能精准检索丹麦高学历职位RSS JSON-LD 双通道 CLI 指南ai job search 实战用 jobbank search 技能精准检索丹麦高学历职位RSS JSON LD 双通道 CLI 指南 本指南以 aAI 应用AI 技能Volcano PDB 插件设计与实现让 reclaim、preempt 和 shuffle 驱逐尊重 PodDisruptionBudgetVolcano PDB 插件设计与实现让 reclaim、preempt 和 shuffle 驱逐尊重 PodDisruptionBudget 本文基于 VoAI 应用AI 技能上一篇GoReleaser v2.5 深度解读Rust 与 Zig 多语言构建支持上线附源码级配置剖析下一篇Android Studio中文界面终极指南告别英文困扰5分钟快速汉化完整教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考