- AI 应用
- AI 技能
【免费下载链接】ai-job-search
The 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.
本文是 ai-job-search 项目内置薪酬基准工具(salary_lookup.py)的实战指南。该工具在/apply求职流程中承担"薪酬对标"职责:把招聘岗位所在公司的薪酬水平,与你自建的薪资基准数据做对比,帮助你在简历筛选与薪资谈判前掌握市场行情。读完本文,你将掌握salary_data.json数据格式的全部字段与约束、三种数据导入方式(手写 JSON / Excel 转换 / 逐步研究)、全部命令行参数的用法,以及底层模糊匹配算法与数据校验器的实现原理。
一、工具定位:可选的薪酬对标步骤
薪酬查询工具(salary_lookup.py)的作用,是将公司薪酬与你自己数据中的基线进行对比。它被集成在/apply工作流中,用于展示"某家公司的薪酬与市场水平相比如何"。
该工具是可选的:如果你没有薪酬数据,/apply流程中的薪酬步骤会被直接跳过,不影响其他求职功能。项目文档 README.md 明确写道:薪酬工具适用于你提供的任何薪酬数据(工会统计、Glassdoor 导出、个人调研等);若没有数据,薪酬步骤即被省略。在 SETUP.md 的安装向导中,薪酬基准被列为可选的第 5 步,同样是"跳过即省略"的语义。
二、工作原理:一份 JSON 数据 + 一个模糊匹配引擎
工具读取仓库根目录下的salary_data.json文件,其中包含公司薪酬基准数据。它使用模糊匹配按公司名查找,能够处理丹麦语/北欧字符(ø、æ、å 等)、法律后缀(A/S、ApS 等)以及常见的拼写变体。
从源码结构看,salary_lookup.py 的匹配管线分为三个可复用的标准化环节(见normalize、anglicize、extract_core_words三个函数):
- normalize(归一化):统一小写、去除空白,并按
STRIP_PATTERNS规则剔除法律后缀与噪音词,包括A/S、ApS、I/S、P/S、K/S、IVS、AMBA/A.M.B.A.(带点写法)、括号内容(如(VG))、地域词(Danmark、Denmark、Scandinavia、Nordic)、通用词(Group、Holding)以及逗号后的子实体描述(salary_lookup.py 中STRIP_PATTERNS定义)。 - anglicize(英文化):按
SPELLING_VARIANTS映射表把丹麦语字符替换为英语等价形式:ø→o、æ→ae、å→aa、ö→o、ä→ae、ü→u,从而让Mærsk与Maersk、Ørsted与Orsted能够互相命中。 - extract_core_words(核心词提取):再次剔除噪音后,提取出长度大于 1 的单词集合,用于词重叠评分。
匹配评分由match_score()计算,得分区间 0~100,search_company()只保留得分 ≥ 30 的结果并按相关度降序排列(salary_lookup.py)。评分层级大致如下(可由 tests/test_salary_lookup.py 中的用例印证):
| 匹配情形 | 分值 |
|---|---|
| 归一化后完全相等(大小写、后缀不影响) | 100 |
英文化后完全相等(如OrstedvsØrsted) | 85 |
| 英文化后互为子串、或短词与核心词重叠 | 75 |
| 归一化后互为子串 | 80 + 长度比×10 |
| 多词重叠(按覆盖比例加权) | 30 ~ 70 |
| 无任何重叠 | 0 |
配套的单元测试覆盖了这些分支:精确匹配返回 100(含MærskvsMærsk A/S、Arla Foods A.M.B.A.vsArla Foods amba)、短查询IBM命中IBM Corporation、Maersk命中Mærsk A/S、无关名称ApplevsVestas Wind Systems返回 0,以及城市过滤的大小写不敏感与英文化匹配(kobenhavn命中København)。
城市过滤
--city参数会做二次过滤:查询城市需出现在条目城市字段中(大小写不敏感),且同样支持英文化匹配;不满足即跳过该条目(见 salary_lookup.py 中search_company的城市判断逻辑)。
三、数据格式:salary_data.json完整说明
工具期望salary_data.json具备如下结构(该示例同时来自 tools/README_SALARY_TOOL.md 的官方模板):
{ "metadata": { "source": "My Union Statistics 2025", "index_baseline": 100, "index_label": "Index", "baseline_description": "Index 100 = median salary for private sector" }, "companies": [ { "company": "Novo Nordisk A/S", "city": "Bagsværd", "categories": { "all_employees": { "count": 500, "index": 108.5 }, "engineering": { "count": 120, "index": 112.3 } } }, { "company": "Ørsted A/S", "city": "Fredericia", "categories": { "all_employees": { "count": 200, "index": 105.2 } } } ] }字段说明
- metadata.source:数据来源说明(仅作参考,如 "My Union Statistics 2025")
- metadata.index_baseline:基线数值,例如索引型数据为 100;若为 0 则表示直接展示绝对值(不计算百分比差)
- metadata.index_label:输出表格中索引列的列名标签
- metadata.baseline_description:基线的人性化解释文字,会打印在输出表格下方
- companies[].company:公司名称(必填,非空字符串)
- companies[].city:城市/地点(可选,用于
--city过滤) - companies[].categories:具名薪酬类别,每个类别包含
count和/或index
数据格式支持任意基于指数或绝对值的薪酬数据,例如:指数 100 = 中位薪酬(越高越好)、你所在币种的绝对薪酬值、或任何你想追踪的自定义指标。index甚至可以是字符串(如隐私保护的"private"),输出时原样显示而不会崩溃(tests/test_salary_lookup.py 的test_text_index_does_not_crash验证了这一点)。
输出表与"vs Baseline"列
当命中公司后,format_entry()会渲染一张对齐的表格(salary_lookup.py),列包括 Category、Count、Index 列与vs Baseline列。百分比差的计算公式为:((index - baseline) / baseline) × 100,正数带+号;当index_baseline为 0 时视为绝对薪酬模式,不显示百分比(测试用例test_format_entry_with_zero_baseline断言不含%)。此外:
- 类别名中的下划线会转为空格并做标题化显示(
all_employees→All Employees); - 若某类别只有
count而没有index,其指数列显示为N/A*,并在表格下方打印脚注* N/A = Too few employees to publish (privacy)——即"员工人数过少,出于隐私不予发布"。脚注只在确实存在被抑制行时才打印(tests/test_salary_lookup.py 用两个用例分别验证了"无抑制行不打印脚注"和"有抑制行必须打印脚注")。
四、数据导入的三种方式
方式 A:手动创建salary_data.json
按第三节的格式手写文件即可,数据可来自任何渠道:工会统计、Glassdoor、薪酬调研、行业人脉信息或个人研究。
方式 B:从 Excel 转换(推荐用于批量数据)
如果你已有 Excel 格式的薪酬数据,使用仓库自带的转换脚本 tools/convert_salary_excel.py:
pip install openpyxl python3 tools/convert_salary_excel.py path/to/salary-data.xlsx \ --source "My Salary Data 2025" \ --baseline 100 \ --baseline-desc "Index 100 = median salary"- 在 Windows 上,若 Python 以
py暴露在 PATH 中则用py;若系统用python而非python3,请相应替换示例命令。 - 默认输出到仓库根目录的
salary_data.json;也可用--output <路径>指定输出文件。 - 转换器会自动探测 Excel 布局:
- 查找 "Company"/"Firma" 列(也识别 virksomhed、employer、arbejdsgiver 等变体)与可选的 "City"/"By" 列(也识别 kommune、location、sted 等,见 tools/convert_salary_excel.py 的
COMPANY_PATTERNS与CITY_PATTERNS); - 其余列视为薪酬数据,并自动配对 count/index 列(如 "Antal alle" 与 "Lønindeks alle" 会被归入同一类别
alle);无类别词的裸 "Count"+"Index"(丹麦语 "Antal"+"Lønindeks")会归入默认类别all_employees,保证单类别布局也正确输出成一行(tests/test_convert_salary_excel.py 中BareCountIndexPairingTests覆盖该场景)。
- 查找 "Company"/"Firma" 列(也识别 virksomhed、employer、arbejdsgiver 等变体)与可选的 "City"/"By" 列(也识别 kommune、location、sted 等,见 tools/convert_salary_excel.py 的
- 转换器内置多项防错保护(均有测试佐证):
- 表头自动定位:会在前 10 行内寻找同时含公司列与城市/计数/指数列的表头行;无交叉佐证时回退到"任一单元格提及公司词"规则。丹麦工会统计导出文件常见的标题/引用行(如 "Kilde: … opdelt efter arbejdsgiver…")不会被误判为表头(对应 issue #414 的回归测试);
- 数字区域解析:支持欧洲/美国两种千分位与小数点写法(
1.234,56与1,234.56都能正确解析),但对单分隔符的歧义写法(如1,234、1.234)采取"宁可跳过、绝不猜错"策略,避免产生 1000 倍误差的薪酬值;丹麦语字符串单元格(如"12,0"、"108,5")也能正确转为数值; - 噪音列排除:自由文本列(如 "Notes")与标识符列(如 "Id"、"personnummer")不会被当作薪酬类别;
- 多工作表支持:逐个解析所有 sheet 并合并输出(tests/test_convert_salary_excel_integration.py 中真实工作簿往返测试覆盖了多 sheet 与元数据写入)。
- 转换完成后,
metadata.index_label固定为"Index",source缺省使用 Excel 文件名(不含扩展名),baseline_description缺省为"Index <baseline> = baseline"。
方式 C:从研究积累起步
从一个空模板开始,随着调研逐步补充公司条目,例如使用绝对值模式:
{ "metadata": { "source": "Personal research", "index_baseline": 0, "index_label": "Monthly salary (DKK)", "baseline_description": "Approximate monthly salary before tax" }, "companies": [ { "company": "Example Corp", "city": "Copenhagen", "categories": { "entry_level": { "index": 42000 }, "senior": { "index": 55000 } } } ] }注意此处index_baseline: 0表示绝对薪酬模式——输出时直接显示数值而不计算百分比差,index_label可自由命名为 "Monthly salary (DKK)" 之类的业务含义标签。
五、命令行用法
主程序支持五个调用形态(salary_lookup.py 的main()中定义):
python3 salary_lookup.py "Novo Nordisk" python3 salary_lookup.py "Ørsted" --city "Fredericia" python3 salary_lookup.py "COWI" --json python3 salary_lookup.py --list-all python3 salary_lookup.py --validate # pre-flight check your salary_data.json各参数说明:
| 参数 | 作用 |
|---|---|
company(位置参数) | 要搜索的公司名;缺省且未使用其他模式时打印帮助信息并退出 |
--city <名称> | 按城市过滤结果(大小写不敏感,支持丹麦语字符英文化匹配) |
--json | 以 JSON 数组输出命中结果(ensure_ascii=False,保留原始字符) |
--list-all | 列出数据集中所有公司名(含城市,若有) |
--validate | 校验salary_data.json并输出报告后退出,不执行查询 |
--validate的行为细节:无问题输出OK - no issues found.并以退出码 0 结束;有问题时分Errors(硬错误,退出码 1)与Warnings(可用性问题但能正常工作,退出码 0)两类报告(salary_lookup.py 的print_validation_report)。典型检查项包括:顶层必须是对象、companies必须是列表、公司名必填且非空、city/categories为对象时类型正确、类别必须是含count和/或index的对象、count必须是数字、重复公司名仅记为警告(tests/test_salary_lookup.py 的ValidateDataTests系列用例逐一验证)。
无结果的提示
当搜索无命中时,工具会提示尝试更短或不同的名称,并提醒数据集中公司名可能包含 "A/S"、"ApS" 等法律后缀;若使用了--city过滤,还会附加提示被城市过滤排除。
六、数据隐私与安全设计
- 数据文件不入库:
salary_data.json已被 .gitignore 排除。你的薪酬数据可能涉及专有或保密信息,因此刻意不纳入版本控制;SETUP.md 也提示应将真正敏感的文件(tracker、薪酬数据、documents/、申请归档等)保存在本地,避免推送到公开 fork。 - 缺失文件的友好降级:若
salary_data.json不存在,salary_lookup.py会打印包含完整指引的错误信息(提示参阅 tools/README_SALARY_TOOL.md),并以退出码 1 结束;/apply工作流随后自动跳过薪酬基准步骤。 - JSON 解析错误无堆栈:非法 JSON 会报告具体行列号(如
invalid JSON at line N, column N),不打印 Python 堆栈,便于用户自查文件(tests/test_salary_lookup.py 的test_load_data_reports_json_parse_errors_without_traceback)。 - UTF-8 输出强制:
main()入口处通过_force_utf8_output()将 stdout/stderr 强制重配为 UTF-8,避免在 Windows 管道输出(默认 ANSI 代码页 cp1252)时因公司名、职位名等含丹麦语字符或非拉丁字符而抛UnicodeEncodeError。tests/test_tools_utf8_output.py 端到端验证了波兰语、西里尔文、中日韩字符均能干净地通过两个工具输出。
七、数据校验与容错边界
validate_data()是查询前的强制关卡(load_data()= 读取 + 解析 + 校验),它把畸形数据挡在查询之前。从collect_validation_issues()的返回设计看,校验器刻意区分两类问题:
- Errors(硬错误):会导致查询崩溃或输出错误,如顶层不是对象、
companies不是列表、类别值不是对象、count非数字等——--validate遇到即退出码 1; - Warnings(软问题):仍然可用,如重复公司名——报告但退出码 0。
值得一提的是容错细节:--validate允许metadata或categories显式为null(与省略等同),而查询渲染路径也必须对null不崩溃——format_entry()内部对 metadata 与 categories 做了空值兜底,并把条目中除company/city/categories外的其他 dict 字段视为类别兜底渲染(tests/test_salary_lookup.py 的NullShapeEndToEndTests验证了"通过 --validate 后查询也能正常渲染"的完整链路)。
八、小结:在求职流程中的使用建议
推荐的最小落地路径:先在 SETUP.md 完成基础安装(项目要求 Python 3.10+),再按需选择一种方式建立salary_data.json(工会统计 Excel 转换最省力,个人调研手动维护最灵活),随后运行python3 salary_lookup.py --validate做一次预检,确认数据合法后即可让/apply流程自动执行薪酬对标。日常使用中,--city可区分同一公司在多地的薪酬差异,--json便于脚本化集成,--list-all可快速浏览数据集全貌。薪酬数据始终留在本地、不入库,既保护了隐私,也让这套基准完全由你掌控。
- AI 应用
- AI 技能
【免费下载链接】ai-job-search
The 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.
相关推荐
5分钟掌握NocoDB全文检索:从模糊查询到精准匹配的实战指南
5分钟掌握NocoDB全文检索:从模糊查询到精准匹配的实战指南 你是否还在为表格数据量大导致搜索卡顿而烦恼?是否因普通查询无法满足复杂检索需求而束手无策?本文将
数据库低代码后端前端Win11Debloat上手实录:10分钟完成Windows 11瘦身,卸载预装应用、关闭遥测与AI
Win11Debloat上手实录:10分钟完成Windows 11瘦身,卸载预装应用、关闭遥测与AI Win11Debloat是一个开源的PowerShell脚
桌面应用CLI在 NNI 中使用 NAS 基准数据集:从数据准备到 Benchmark 查询与算法评估
在 NNI 中使用 NAS 基准数据集:从数据准备到 Benchmark 查询与算法评估 NAS(Neural Architecture Search)算法验证
人工智能AutoML机器学习深度学习模型压缩特征工程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考