您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
to show hr lastest login time,help you deliver your resume efficiently.
当前为
// ==UserScript== // @name showBossActiveTime // @namespace http://www.chensong.cc/ // @version 0.4 // @description to show hr lastest login time,help you deliver your resume efficiently. // @author chensong // @match https://www.zhipin.com/web/geek/job* // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== // @grant GM_xmlhttpRequest // @license MIT // ==/UserScript== (function () { 'use strict'; class ShowBossActiveTime { constructor(options) { this.isUpdating = false; this.statusOptions = localStorage .getItem('bossActiveStatusList') ?.split(',') || [ '半年前活跃', '近半年活跃', '4月前活跃', '2月内活跃', '2周内活跃' ]; this.removeStatusList = []; this.options = Object.assign( { listElement: '.job-card-wrapper', onlineElement: '.boss-online-tag', chatElement: '.start-chat-btn', hunterElement: '.job-tag-icon', linkElement: '.job-card-left', paginationElement: '.options-pages', hideChated: false }, options ); this.queque = []; //查询队列 this.list = []; //数据列表 //添加过滤条件,因为要保存选择数据,所以这个不能切换时清空 this.addStatusFilter(); this.addStyleSheet(); // 监听请求数据事件 this.observeLoadingData(); this.request = this.requestInit(); this.init(); } addStyleSheet() { const style = ` .show-active-status{display:flex;padding:5px 10px;background:#e1f5e3;color:green;width:80%;border-radius:4px;margin-top:10px;} .show-active-status .status{} .show-active-status .chat{} #alertBox{position: fixed; top: 20%; left: 50%; transform: translate(-50%, -50%); background-color: rgb(0 190 189); border-radius: 5px; color: #fff; z-index: 9999; padding: 20px 40px; font-size: 20px; box-shadow: 0px 0px 10px rgba(0,0,0,.2);} #removeFilterDataContainer{ position: fixed;right: 70px;top: 70px;z-index: 20000;background: #00bebd; color: #fff;display: flex;flex-direction: column;padding-bottom:10px } #removeFilterDataContainer.hide{height:28px;overflow:hidden} #removeFilterDataContainer .title {display:flex;justify-content: space-around;} #removeFilterDataContainer .title label{align-items:center;padding:0 15px;} #removeFilterDataContainer.hide #boss-active-time-arrow svg{transform: rotate(180deg);} #removeFilterDataContainer #boss-active-time-arrow {cursor: pointer;font-size: 24px;background: #009796;padding:2px 10px;line-height:1;} #removeFilterDataContainer .tips{font-size:16px;margin:5px 20px;} #removeFilterDataContainer label{display:flex;padding:0 20px;} #removeFilterDataContainer label input{margin-right:5px;} `; const styleEle = document.createElement('style'); styleEle.id = 'show-boss-active-time-css'; styleEle.innerHTML = style; document.head?.appendChild(styleEle); } // 获取节点列表 getList() { Array.from(document.querySelectorAll(this.options.listElement)).forEach( (node, index) => { const status = node.querySelector(this.options.onlineElement); this.list.push(node); // 不在线 if (!status) { this.queque.push(node); } } ); } // 设置文本内容 setText(node, text, status) { const html = ` <div class="show-active-status"> <p class="status">${text}</p> <p class="chat">${status}</p> </div> `; node.querySelector('.job-info').insertAdjacentHTML('afterend', html); let aEle = node.querySelector('a'); aEle.style.height = 'auto'; aEle.style.paddingBottom = '0'; if(!this.statusOptions.includes(text)&&text!=='在线'){ this.statusOptions.push(text); localStorage.setItem('bossActiveStatusList',this.statusOptions); } } async getListStatus() { this.alertBox('开始更新状态....,网站安全策略问题,更新会比较缓慢。'); this.isUpdating = true; for (let i = 0; this.queque.length > 0; i++) { let node = this.queque.shift(); let link = node.querySelector(this.options.linkElement).href; let chat = node.querySelector(this.options.chatElement).textContent; await new Promise((resolve) => { setTimeout(async () => { /*做个延时处理,频繁请求会触发302重定向,最终导致拿不到html页面数据*/ await this.request(link, node, chat, this.queque.length); resolve(); }, 1000); }); } if (this.queque.length === 0) { this.isUpdating = false; this.alertBox('查询完毕,更新即将完成'); } } requestInit(){ //如果是油猴,使用GM_xmlhttpRequest,如果不是,使用fetch if (window.GM_xmlhttpRequest) { return (link, node, chat, index) => { return GM_xmlhttpRequest({ method: 'GET', url: link, onload: (response) => { if (/security-check.html/.test(response.finalUrl)) { // 用GM_xmlhttpRequest获取触发了302,用finaleUrl通过iframe来获取,不用link,看是否能省略302这个步骤,加快速度 this.getStatusByIframe(response.finalUrl, index).then( (text) => { if (text === '') { text = '未知状态'; } this.setText(node, text, chat); } ); } else { const html = response.responseText; const parser = new DOMParser(); const doc = parser.parseFromString(html, 'text/html'); const text = this.getStatusText(doc); this.setText(node, text, chat); } } }); }; } else { return (link, node, chat, index) => { /*设置不允许重定向,让其报错,报错后通过iframe来获取数据,虽然慢点,但起码可以获取到数据*/ return fetch(link, { redirect: 'error' }) .then((res) => { return res.text(); }) .then(async (data) => { const doc = document.createElement('div'); doc.insertAdjacentHTML('afterbegin', data); const text = this.getStatusText(doc); this.setText(node, text, chat); }) .catch(async (error) => { /*请求被302临时重定向了,无法获取到数据,需要用iframe来获取了*/ this.getStatusByIframe(link, index).then((text) => { if (text === '') { text = '未知状态'; } this.setText(node, text, chat); }); }); }; } } async getStatusByIframe(link, id) { let iframe = document.createElement('iframe'); iframe.src = link; iframe.id = 'tempIframe' + id; iframe.style.cssText = 'width:0;height:0;'; document.body.appendChild(iframe); return await new Promise((resolve) => { let tempIframe = document.querySelector('#tempIframe' + id); tempIframe.onload = () => { setTimeout(() => { if (tempIframe.contentWindow?.document) { const text = this.getStatusText( tempIframe.contentWindow.document ); resolve(text); console.log('用iframe获取', text); setTimeout(() => { document.body.removeChild(tempIframe); }, 500); } }, 5000); }; }); } observeLoadingData() { const container = document.querySelector('.search-job-result'); const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { if (mutation.type === 'childList') { const addNode = mutation.addedNodes; const removedNode = mutation.removedNodes; if ( addNode.length && addNode[0].className === 'job-loading-wrapper' ) { console.log('触发了请求列表数据'); } if ( removedNode.length && removedNode[0].className === 'job-loading-wrapper' ) { console.log('加载完成'); this.clear(); this.init(); } } }); }); const config = { attributes: false, childList: true, subtree: false }; observer.observe(container, config); } alertBox(msg) { let div = document.createElement('div'); div.id = 'alertBox'; div.innerHTML = msg; document.body.appendChild(div); setTimeout(function () { document.body.removeChild(div); }, 2000); } getStatusText(doc) { const timeNode = doc.querySelector('.boss-active-time'); if (timeNode) { return timeNode.textContent; } else { // 没有获取到状态,但页面是已经加载到的了 const isHunter = ['.certification-tags', '.boss-info-attr'].filter( (name) => { const node = doc.querySelector(name); return /猎头|人力|经纪/.test(node?.textContent); } ); const status = isHunter ? '猎头,没有活跃状态' : '获取到数据了,但不知道是什么数据'; return status; } } toggleChated() { this.list.forEach((node) => { const chat = node.querySelector(this.options.chatElement).textContent; if (this.options.hideChated && chat === '继续沟通') { node.style.display = 'none'; } else { node.style.display = 'block'; } }); } addStatusFilter() { const container = document.createElement('div'); container.id = 'removeFilterDataContainer'; const html = ` <label><input type="checkbox" name="hideChated" value="1">过滤已经沟通过的</label> <div id="boss-active-time-arrow"><svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" aria-hidden="true" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7"></path></svg></div> `; const title = document.createElement('div'); title.className = 'title'; title.innerHTML = html; const tips = document.createElement('div'); tips.innerHTML = '过滤掉勾选的数据'; tips.className = 'tips'; container.appendChild(title); container.appendChild(tips); container .querySelector('#boss-active-time-arrow') .addEventListener('click', function () { container.classList.contains('hide') ? container.classList.remove('hide') : container.classList.add('hide'); }); this.statusOptions.forEach((option) => { const label = document.createElement('label'); const el = document.createElement('input'); el.type = 'checkbox'; el.name = option; el.value = option; el.className = 'status-checkbox'; label.appendChild(el); label.appendChild(document.createTextNode(option)); container.appendChild(label); }); const loopDom = () => { this.list.forEach((node) => { const status = node.querySelector('.status')?.textContent; const chat = node.querySelector('.chat')?.textContent; if (status && chat) { if (this.removeStatusList.includes(status)) { node.style.display = 'none'; } else { node.style.display = 'block'; } if (this.options.hideChated && chat === '继续沟通') { node.style.display = 'none'; } } }); }; container.addEventListener('change', () => { const selectedValues = Array.from( container.querySelectorAll('.status-checkbox:checked') ).map((el) => el.value); this.removeStatusList = selectedValues; const hideNode = document.querySelector('input[name="hideChated"]'); this.options.hideChated = hideNode?.checked; loopDom(); // 如果正在更新,需要定时器定时查询最新数据,不然后面更新的数据不能触发loopDom if (this.isUpdating) { const timer = setInterval(() => { // 如果已经更新完毕,清除定时器,这里面多次选择会触发多个定时器,可以把timer提到外面避免这个问题,但因为实际使用中,重复调用的代价并不明显,也因为懒,就不提出到外面了 if (!this.isUpdating) { clearInterval(timer); } loopDom(); }, 1000); } }); document.body.appendChild(container); } clear(){ this.queque.length = 0; this.list.length = 0; this.isUpdating = false; } init() { // 获取列表数据 this.getList(); // 判断是否要隐藏已经沟通过的数据 this.toggleChated(); // 先给在线的数据设置状态 this.list.forEach((node) => { const chat = node.querySelector(this.options.chatElement).textContent; const online = node.querySelector(this.options.onlineElement); if (online) { this.setText(node, '在线', chat); } }); // 请求数据,给不在线的设置状态 this.getListStatus(); } } function start() { const Lis = document.querySelectorAll('.job-card-wrapper'); if (Lis.length) { new ShowBossActiveTime(); } else { console.log('no start'); setTimeout(start, 2000); } } start(); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址