Greasy Fork is available in English.
深度破解 Boss 直聘 CSS 隐藏干扰词反爬,提取精准干净的 JD 与 HR 信息
// ==UserScript==
// @name Boss直聘JD/HR信息精准提取 (智能反混淆版)
// @namespace http://tampermonkey.net/
// @version 2.3
// @description 深度破解 Boss 直聘 CSS 隐藏干扰词反爬,提取精准干净的 JD 与 HR 信息
// @author Padiya (Modified by Henry)
// @match https://www.zhipin.com/web/geek/jobs*
// @match https://www.zhipin.com/job_detail/*
// @match https://www.zhipin.com/gongsi/job/*
// @grant GM_setClipboard
// @license MIT
// ==/UserScript==
(function() {
'use strict';
// 1. 采用高容错率的相对类名选择器
const PAGE_CONFIGS = {
'job-recommend': {
jdSelector: '.job-detail-box .job-detail-body .desc, .job-detail-body .job-sec-text',
hrSelector: '.job-detail-box .job-boss-info .name, .job-boss-info h2',
companyTitleSelector: '.job-detail-box .job-boss-info .boss-info-attr'
},
'job_detail': {
jdSelector: '.job-sec-text',
hrSelector: '.job-boss-info h2',
companyTitleSelector: '.job-boss-info .boss-info-attr'
},
'gongsi': {
jdSelector: '.job-detail-body .desc',
hrSelector: '.job-detail-body .job-boss-info .name',
companyTitleSelector: '.job-detail-body .job-boss-info .boss-info-attr'
}
};
function createStyle() {
const style = document.createElement('style');
style.innerHTML = `
#boss-extractor-btn {
position: fixed; bottom: 30px; right: 30px; z-index: 9999;
padding: 12px 24px; background: linear-gradient(135deg, #00bebd, #00a6a7);
color: white; border: none; border-radius: 50px;
font-size: 16px; font-weight: bold; cursor: pointer;
box-shadow: 0 4px 15px rgba(0, 190, 189, 0.4); transition: all 0.3s ease;
}
#boss-extractor-btn:hover { transform: translateY(-3px); box-shadow: 0 6px 20px rgba(0, 190, 189, 0.6); }
#boss-extractor-btn:active { transform: translateY(1px); }
.boss-tooltip {
position: fixed; bottom: 90px; right: 30px; z-index: 10000;
padding: 12px 20px; background: #333; color: white; border-radius: 8px;
font-size: 14px; box-shadow: 0 4px 12px rgba(0,0,0,0.15);
animation: fadeIn 0.3s, fadeOut 0.3s 2s forwards;
}
@keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
@keyframes fadeOut { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(-10px); } }
`;
document.head.appendChild(style);
}
function showTooltip(message) {
let tooltip = document.querySelector('.boss-tooltip');
if (tooltip) tooltip.remove();
tooltip = document.createElement('div');
tooltip.className = 'boss-tooltip';
tooltip.textContent = message;
document.body.appendChild(tooltip);
setTimeout(() => tooltip.remove(), 2500);
}
function cleanHRName(text) {
if (!text) return '未找到HR信息';
// 清除状态后缀并安全获取第一行
const cleanText = text.replace(/刚刚活跃|今日活跃|在线/g, '');
return cleanText.split('\n')[0].trim();
}
function parseCompanyAndTitle(text) {
if (!text) return { company: '未找到公司信息', title: '未找到头衔信息' };
const parts = text.trim().split('·').map(p => p.trim()).filter(p => p);
if (parts.length >= 2) return { company: parts[0], title: parts[1] };
return { company: parts[0] || '未找到公司信息', title: '未找到头衔信息' };
}
function getCurrentPageConfig() {
const url = window.location.href;
if (url.includes('gongsi')) return PAGE_CONFIGS['gongsi'];
if (url.includes('job_detail')) return PAGE_CONFIGS['job_detail'];
if (url.includes('job-recommend')) return PAGE_CONFIGS['job-recommend'];
return PAGE_CONFIGS['job-recommend']; // 默认 fallback
}
// 核心反爬破解逻辑:动态解析 CSS,精准剔除隐藏词
function getCleanText(element) {
if (!element) return '未找到信息';
const clone = element.cloneNode(true);
// 1. 获取并解析植入的隐藏样式类名
const styles = clone.querySelectorAll('style');
const hiddenClasses = new Set();
styles.forEach(style => {
const cssText = style.textContent;
// 匹配 .类名 { ... display:none ... } 或 .类名 { ... visibility:hidden ... }
const regex = /\.([a-zA-Z0-9_-]+)[^{]*\{[^}]*(?:display:\s*none|visibility:\s*hidden|width:\s*0|font-size:\s*0)[^}]*\}/gi;
let match;
while ((match = regex.exec(cssText)) !== null) {
if (match[1]) hiddenClasses.add(match[1]);
}
style.remove(); // 解析完后移除 style 标签自身
});
// 2. 遍历所有 span,仅移除被判定为"隐藏类"的干扰标签,保留真实的单字标签
const spans = clone.querySelectorAll('span');
spans.forEach(span => {
let isFake = false;
span.classList.forEach(className => {
if (hiddenClasses.has(className)) {
isFake = true;
}
});
if (isFake) {
span.remove(); // 靶向移除(如 "kanzhun", "直聘")
}
});
// 3. 将 <br> 替换为换行符,保证输出到剪贴板时的排版整洁
const brs = clone.querySelectorAll('br');
brs.forEach(br => br.replaceWith('\n'));
// 4. 清理多余空行
return clone.textContent ? clone.textContent.replace(/\n\s*\n/g, '\n\n').trim() : '未找到信息';
}
// 获取并组合第一页选中的工作内容
function getJobInfo() {
const config = getCurrentPageConfig();
if (!config) return '当前页面不支持信息提取';
// 使用 querySelector 自动获取第一个匹配的节点
const jdElement = document.querySelector(config.jdSelector);
const hrElement = document.querySelector(config.hrSelector);
const companyTitleElement = document.querySelector(config.companyTitleSelector);
const jdContent = getCleanText(jdElement);
const hrContent = cleanHRName(getCleanText(hrElement));
const { company, title } = parseCompanyAndTitle(getCleanText(companyTitleElement));
return `【职位描述】\n${jdContent}\n\n【招聘员信息】\n${hrContent} / 职位:${title}\n\n【公司信息】\n${company}`;
}
function init() {
createStyle();
const button = document.createElement('button');
button.id = 'boss-extractor-btn';
button.textContent = '📋 提取JD/HR信息';
document.body.appendChild(button);
button.addEventListener('click', function() {
const jobInfo = getJobInfo();
GM_setClipboard(jobInfo, 'text');
showTooltip('✅ 复制成功!结构与文字已精准解析');
});
}
// 延迟一点点执行,确保页面 DOM 彻底加载完毕
setTimeout(init, 1000);
})();