背景:这段时间找工作,无奈大环境不好,所在城市大部分公司都投了。就是没几个回复的,要么送达,要么已读不回,要么拿了简历没见邀约。然后boss为了争取我们多浏览网站,把一些陈年老醋也拿上台面,让我们误以为有新公司发布职位,结果一点击进去,什么本月活跃,4月内活跃,半年活跃,这些明显就已经不招或者已经招到,只是hr忘了关闭岗位的。还不给过滤条件我们来过滤掉这些岗位,浪费我们时间。
为了过滤一下这些数据,只好自己动手丰衣足食。原理很简单,就是用js代码把没有活跃状态的列表数据用css都给隐藏掉,避免影响我们观感。代码也简单。还有为了不每次都得输入代码,我们要把对应的代码保存到浏览器书签。这样就可以通过点击书签来快速便捷地执行js代码。具体操作就是随意新建一个书签,然后到书签栏找到书签,修改书签。
书签名随你心意,重点是地址栏要把url替换成代码块里面的代码。
javascript: (function() {
function filterOnlineList() {
let lis = document.querySelectorAll(".job-card-wrapper");
for (let i = 0; i < lis.length; i++) {
let online = lis[i].querySelector('.boss-online-tag');
if (!online) {
lis[i].style.display = 'none'
}
}
alertBox('过滤成功');
}
function alertBox(msg) {
var div = document.createElement('div');
div.style.position = 'fixed';
div.style.top = '20%';
div.style.left = '50%';
div.style.transform = 'translate(-50%, -50%)';
div.style.backgroundColor = 'rgb(0 190 189)';
div.style.borderRadius = '5px';
div.style.color = '#fff';
div.style.zIndex = 9999;
div.style.padding = '20px 100px';
div.style.fontSize = '20px';
div.style.boxShadow = '0px 0px 10px rgba(0,0,0,.2)';
div.innerHTML = msg;
document.body.appendChild(div);
setTimeout(function() {
document.body.removeChild(div);
},
1000);
}
function reBindClick() {
let pages = document.querySelectorAll('.options-pages a');
console.log("因为分页每次点击都会重新渲染,所以需要点击后用定时器重新触发绑定点击事件,不然点击后就没有点击事件监听了");
for (let i = 0; i < pages.length; i++) {
pages[i].addEventListener('click',
function() {
setTimeout(function() {
reBindClick();
filterOnlineList();
},
1000);
})
}
}
reBindClick();
filterOnlineList();
})()
不保证后续代码会不会失效,但原理都是相同的,仔细看一下代码就知道如果失效了,该怎么改,本来是想看能不能过滤不仅限于在线状态的,还有一些3日,本周,本月活跃之类的,但仔细看过接口后发现查询列表接口没返回这个状态,只有一个online的布尔值。其它的数据是后端渲染html页面生成的数据,不是通过接口返回的数据,所以就没办法,只能退而求之。
注意:如果你们需要修改代码,要注意以下几点,代码结束分号要有,不然可能会报错。好像也无法使用window,可能是chrome的安全考虑。前面的javascript:是必须的,不然点击书签的时候,浏览器不会执行代码,这里加了个提示框来提示代码是否有成功执行,不用提示框也是可以的,只是可能不知道有没有执行成功
进阶版
后面又想了下,折腾了有一天多吧,算是折腾出一个更好一点的版本
思路都注释在代码里面了。用的fetch去获取对应的html页面,再从html页面里面拿出对应的数据,原理简单,但中间经历的坑也是不少的。
坑一,也是最主要的坑:boss的html页面如果获取速度慢了,会给个302的临时重定向返回回来,你们看到的效果就是点击查询列表页面的任意一个打开的页面会显示一个loading的效果,实际这个loading就是重定向的一个页面,后面它响应到资源了才会再重定向回来目标页面,用户无感,但是对于我们这种只是想拿点数据的就是灾难了,因为它一重定向,浏览器就自动重定向,我们就拿不到数据。最后只能是fetch可以拿到数据的就fetch,fetch拿不到数据了就用iframe加载实际页面,拿到数据后,再删除iframe.
坑二:不能短时间内频繁触发请求,不然所有请求都给你弄成302,所以我只好牺牲速度,保证效果,用Promise await慢慢获取数据,避免触发boss的302 策略。
坑三:用iframe也有坑,本来想用DOMContentLoaded来加快循环速度的,就是拿到html就可以了,因为所需数据就在html页面,不需要css js 图片那些乱七八糟的东西,计划拿完就删掉它,浏览器自然就取消请求了。结果实验了却监听不了这个,最后还是老老实实用回onload,可是用回onload也还是有坑,用iframe加载页面,某些页面也会触发302,这时候你立马去拿值,是拿不到值的,因为真正的页面还没回来,所以只好又用定时器再延时获取一下数据,但这个时间实在不好把控,还有每次拿完要删了iframe,不然你后面再用这个iframe,不会触发onload。
坑四:有些hr是没有状态的,例如一些猎头还有一些奇怪的hr,是空值来的
贴一下效果图,样式随便弄了一下
压缩书签版本,复制到书签去的版本
javascript:(function(){function initBossHrStatus(){let isPageChange=false;function alertBox(msg){var div=document.createElement('div');div.style.cssText='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 100px; font-size: 20px; box-shadow: 0px 0px 10px rgba(0,0,0,.2);';div.innerHTML=msg;document.body.appendChild(div);setTimeout(function(){document.body.removeChild(div)},2000)}function reBindClick(){let pages=document.querySelectorAll('.options-pages a');for(let i=0;i<pages.length;i++){pages[i].addEventListener('click',function(){isPageChange=true;setTimeout(function(){new initBossHrStatus()},1000)})}}async function getListStatus(){alertBox('开始更新状态....,网站安全策略问题,更新会比较缓慢。');let links=Array.from(document.querySelectorAll('.job-list-box .job-card-left')).filter((node)=>{let online=node.querySelector('.boss-online-tag');if(online){setText(node,'在线')}return!online});function setText(node,statusTxt){let pNode=document.createElement('p');pNode.innerHTML=statusTxt;console.log(statusTxt);pNode.style.cssText="display:flex;padding:5px;background:#e1f5e3;color:green;";node.querySelector('.job-info').after(pNode)}for(let i=0;i<links.length;i++){if(isPageChange){break}await new Promise((resolve)=>{setTimeout(()=>{resolve()},2000)});let node=links[i];let link=node.href;let statusTxt=await getHtml(link);console.log(statusTxt);if(statusTxt===''){statusTxt='未知状态'}setText(node,statusTxt);if(i===links.length){alertBox('更新完成')}}}function getHtml(link){function fetchHtml(){return fetch(link,{redirect:'error'}).then((res)=>{return res.text()}).then(async(data)=>{const divNode=document.createElement("div");divNode.insertAdjacentHTML('afterbegin',data);const node=divNode.querySelector('.boss-active-time');return node?node.textContent:'猎头,或者没状态的hr'}).catch(async(error)=>{return await getStatusByIframe(link)})}return fetchHtml()}async function getStatusByIframe(link){let iframe=document.createElement('iframe');iframe.src=link;iframe.id='tempIframe';iframe.style.cssText="width:0;height:0;";document.body.appendChild(iframe);return await new Promise((resolve)=>{let iframe=document.querySelector('#tempIframe');iframe.onload=function(){let node=iframe.contentWindow.document.querySelector('.boss-active-time');function returnVal(){let status=node?node.textContent:'可能不存在状态,也可能没获取到真实数据,大概率后者';resolve(status);setTimeout(()=>{document.body.removeChild(iframe)},500)}if(node){returnVal()}else{setTimeout(()=>{node=iframe.contentWindow.document.querySelector('.boss-active-time');returnVal()},2000)}}})}reBindClick();getListStatus();return true}new initBossHrStatus()})()
源码版,给你们看代码的
javascript: (function() {
function initBossHrStatus(){
let isPageChange = false;
function alertBox(msg) {
var div = document.createElement('div');
div.style.cssText = '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 100px; font-size: 20px; box-shadow: 0px 0px 10px rgba(0,0,0,.2);';
div.innerHTML = msg;
document.body.appendChild(div);
setTimeout(function() {
document.body.removeChild(div);
},
2000);
}
function reBindClick() {
let pages = document.querySelectorAll('.options-pages a');
/*因为分页每次点击都会重新渲染,所以需要点击后用定时器重新运行方法"*/
for (let i = 0; i < pages.length; i++) {
pages[i].addEventListener('click',
function() {
isPageChange = true;
setTimeout(function() {
new initBossHrStatus();
},
1000);
})
}
}
async function getListStatus(){
alertBox('开始更新状态....,网站安全策略问题,更新会比较缓慢。');
let links = Array.from(document.querySelectorAll('.job-list-box .job-card-left')).filter((node)=>{
let online = node.querySelector('.boss-online-tag');
if(online){
setText(node,'在线');
}
return !online;
});
function setText(node,statusTxt){
let pNode = document.createElement('p');
pNode.innerHTML = statusTxt;
console.log(statusTxt);
pNode.style.cssText = "display:flex;padding:5px;background:#e1f5e3;color:green;";
node.querySelector('.job-info').after(pNode);
}
/*要把在线的过滤掉,一来减少请求,二来请求的数据也不存在下面代码的class .boss-active-time,会报错'*/
for (let i = 0; i < links.length; i++) {
if(isPageChange){
/*切换了分页, 要中断循环*/
break;
}
await new Promise((resolve) => {
setTimeout(()=>{
/*做个延时处理,好像boss有做ddos处理,频繁请求会触发302重定向,最终导致拿不到html页面数据*/
resolve();
}, 2000);
});
let node = links[i];
let link = node.href;
let statusTxt = await getHtml(link);
console.log(statusTxt);
if(statusTxt===''){
statusTxt = '未知状态';
}
setText(node,statusTxt);
if(i===links.length){
alertBox('更新完成');
}
}
}
function getHtml(link){
function fetchHtml(){
/*设置不允许重定向,让其报错,报错后通过iframe来获取数据,虽然慢点,但起码可以获取到数据*/
return fetch(link, { redirect: 'error' })
.then((res)=>{
return res.text();
}).then(async(data)=>{
const divNode = document.createElement("div");
divNode.insertAdjacentHTML('afterbegin', data);
const node = divNode.querySelector('.boss-active-time');
return node?node.textContent:'猎头,或者没状态的hr';
}).catch(async(error)=>{
/*请求被302临时重定向了,无法获取到数据,需要用iframe来获取了*/
return await getStatusByIframe(link);
})
}
return fetchHtml();
}
async function getStatusByIframe(link){
let iframe = document.createElement('iframe');
iframe.src = link;
iframe.id = 'tempIframe';
iframe.style.cssText = "width:0;height:0;";
document.body.appendChild(iframe);
return await new Promise((resolve)=>{
let iframe = document.querySelector('#tempIframe');
iframe.onload = function(){
let node = iframe.contentWindow.document.querySelector('.boss-active-time');
function returnVal(){
let status = node?node.textContent:'可能不存在状态,也可能没获取到真实数据,大概率后者';
resolve(status);
setTimeout(()=>{
document.body.removeChild(iframe);
},500)
}
if(node){
returnVal();
}else{
/*应该是iframe页面也触发了302临时重定向,导致这时候获取,不能拿到真正的数据,所以延迟试试,但这个延时不好控制,调小了,获取不到数据,调大了,显得反应很慢(不过慢其实没啥影响,因为你不可能一下子浏览全部列表数据,一条一条来,应该是可以的)*/
setTimeout(()=>{
node = iframe.contentWindow.document.querySelector('.boss-active-time');
returnVal();
},2000)
}
}
})
}
reBindClick();
getListStatus();
return true;
}
/*虽然反应速度可能不是很理想,但只是个小功能,所以有效果就行,不想继续优化了*/
new initBossHrStatus();
})()
我又更新了。。。。,应该是最终版了吧
书签版
(function(){'use strict';function showBossActiveTime(){let isPageChange=false;function getLis(){let links=Array.from(document.querySelectorAll('.job-list-box .job-card-left')).filter((node)=>{let online=node.querySelector('.boss-online-tag');if(online){setText(node,'在线')}return!online});return links}function setText(node,statusTxt){let pNode=document.createElement('p');pNode.innerHTML=statusTxt;console.log(statusTxt);pNode.style.cssText='display:flex;padding:5px 10px;background:#e1f5e3;color:green;width:80%;border-radius:4px;margin-top:10px;';node.querySelector('.job-info').after(pNode);pNode.parentNode.style.height='auto';pNode.parentNode.style.paddingBottom='0'}async function getListStatus(){alertBox('开始更新状态....,网站安全策略问题,更新会比较缓慢。');let links=getLis();for(let i=0;i<links.length;i++){if(isPageChange){break}let node=links[i];let link=node.href;await new Promise((resolve)=>{setTimeout(async()=>{fetch(link).then((res)=>{if(res.redirected){throw new Error(res.url);}return res.text()}).then(async(data)=>{const divNode=document.createElement('div');divNode.insertAdjacentHTML('afterbegin',data);const statusText=getStatusText(divNode);setText(node,statusText)}).catch(async(error)=>{getStatusByIframe(error.message,i).then((res)=>{if(res===''){res='未知状态'}setText(node,res)})});resolve()},1000)});if(i===links.length-1){alertBox('更新完成')}}}async function 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=function(){setTimeout(()=>{if(tempIframe.contentWindow?.document){const statusText=getStatusText(tempIframe.contentWindow.document);resolve(statusText);console.log('用iframe获取',statusText);setTimeout(()=>{document.body.removeChild(tempIframe)},500)}},5000)}})}function pageBtnBindClick(){let pages=document.querySelectorAll('.options-pages a');for(let i=0;i<pages.length;i++){pages[i].addEventListener('click',function(){isPageChange=true;setTimeout(function(){showBossActiveTime()},1000)})}}function alertBox(msg){var div=document.createElement('div');div.style.cssText='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 100px; font-size: 20px; box-shadow: 0px 0px 10px rgba(0,0,0,.2);';div.innerHTML=msg;document.body.appendChild(div);setTimeout(function(){document.body.removeChild(div)},2000)}function getStatusText(doc){const timeNode=doc.querySelector('.boss-active-time');if(timeNode){console.log('用接口获取',timeNode.textContent);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}}function init(){pageBtnBindClick();getListStatus()}init()}showBossActiveTime()})();
源码版
(function () {
'use strict';
function showBossActiveTime() {
let isPageChange = false;
function getLis() {
/*要把在线的过滤掉,一来减少请求,二来请求的数据也不存在下面代码的class .boss-active-time,会报错'*/
let links = Array.from(
document.querySelectorAll('.job-list-box .job-card-left')
).filter((node) => {
let online = node.querySelector('.boss-online-tag');
if (online) {
setText(node, '在线');
}
return !online;
});
return links;
}
function setText(node, statusTxt) {
let pNode = document.createElement('p');
pNode.innerHTML = statusTxt;
console.log(statusTxt);
pNode.style.cssText =
'display:flex;padding:5px 10px;background:#e1f5e3;color:green;width:80%;border-radius:4px;margin-top:10px;';
node.querySelector('.job-info').after(pNode);
pNode.parentNode.style.height = 'auto';
pNode.parentNode.style.paddingBottom = '0';
}
async function getListStatus() {
alertBox('开始更新状态....,网站安全策略问题,更新会比较缓慢。');
let links = getLis();
for (let i = 0; i < links.length; i++) {
if (isPageChange) {
/*切换了分页, 要中断循环*/
break;
}
let node = links[i];
let link = node.href;
await new Promise((resolve) => {
setTimeout(async () => {
/*做个延时处理,频繁请求会触发302重定向,最终导致拿不到html页面数据*/
fetch(link)
.then((res) => {
if (res.redirected) {
throw new Error(res.url);
}
return res.text();
})
.then(async (data) => {
const divNode = document.createElement('div');
divNode.insertAdjacentHTML('afterbegin', data);
const statusText = getStatusText(divNode);
setText(node, statusText);
})
.catch(async (error) => {
getStatusByIframe(error.message, i).then((res) => {
if (res === '') {
res = '未知状态';
}
setText(node, res);
});
});
resolve();
}, 1000);
});
if (i === links.length - 1) {
alertBox('更新完成');
}
}
}
async function 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 = function () {
setTimeout(() => {
if (tempIframe.contentWindow?.document) {
const statusText = getStatusText(
tempIframe.contentWindow.document
);
resolve(statusText);
console.log('用iframe获取', statusText);
setTimeout(() => {
document.body.removeChild(tempIframe);
}, 500);
}
}, 5000);
};
});
}
function pageBtnBindClick() {
let pages = document.querySelectorAll('.options-pages a');
/*因为分页每次点击都会重新渲染,所以需要点击后用定时器重新运行方法"*/
for (let i = 0; i < pages.length; i++) {
pages[i].addEventListener('click', function () {
isPageChange = true;
setTimeout(function () {
showBossActiveTime();
}, 1000);
});
}
}
function alertBox(msg) {
var div = document.createElement('div');
div.style.cssText =
'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 100px; font-size: 20px; box-shadow: 0px 0px 10px rgba(0,0,0,.2);';
div.innerHTML = msg;
document.body.appendChild(div);
setTimeout(function () {
document.body.removeChild(div);
}, 2000);
}
function getStatusText(doc) {
const timeNode = doc.querySelector('.boss-active-time');
if (timeNode) {
console.log('用接口获取', timeNode.textContent);
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;
}
}
function init() {
pageBtnBindClick();
getListStatus();
}
init();
}
showBossActiveTime();
})();
有同学说要油猴版,又去看了下油猴怎么弄
油猴脚本的链接:showBossActiveTime
git项目地址: GitHub - shrimpbighead/showBossActiveTime