给boss直聘的搜索结果加上hr活跃状态,少看点半年活跃的岗位,有书签版,油猴版

背景:这段时间找工作,无奈大环境不好,所在城市大部分公司都投了。就是没几个回复的,要么送达,要么已读不回,要么拿了简历没见邀约。然后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();
})()

我又更新了。。。。,应该是最终版了吧

书签版

javascript:(function(){'use strict';class ShowBossActiveTime{constructor(options){this.startTime=null;this.statusOptions=localStorage.getItem('bossActiveStatusList')?.split(',').filter(t=>t.length)||['半年前活跃','近半年活跃','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>&nbsp;&nbsp;&nbsp;&nbsp;<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('开始更新状态....,网站安全策略问题,更新会比较缓慢。');const startTime=new Date().getTime();this.startTime=startTime;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()=>{await this.request(link,node,chat,this.queque.length);resolve()},1000)});if(startTime!==this.startTime){return}}if(this.queque.length===0){this.startTime=null;setTimeout(()=>{this.alertBox('查询完毕,更新即将完成')},1500)}}requestInit(){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)){this.getStatusByIframe(response.finalUrl,index).then((text)=>{if(text===''){text='未知状态'}this.setText(node,text,chat);this.toggleDom(node)})}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);this.toggleDom(node)}}})}}else{return(link,node,chat,index)=>{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);this.toggleDom(node)}).catch(async(error)=>{this.getStatusByIframe(link,index).then((text)=>{if(text===''){text='未知状态'}this.setText(node,text,chat);this.toggleDom(node)})})}}}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);const listContainer=document.querySelector('#wrap');const listObserver=new MutationObserver((mutations)=>{mutations.forEach((mutation)=>{if(mutation.type==='childList'){const wrapper=document.querySelector('.job-list-wrapper');const removeNode=document.querySelector("#removeFilterDataContainer");if(!wrapper&&removeNode){document.body.removeChild(removeNode);listObserver.disconnect();this.clear()}}})});listObserver.observe(listContainer,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}}toggleDom(node){const status=node.querySelector('.status')?.textContent;const chat=node.querySelector(this.options.chatElement).textContent;node.style.display='block';if(this.options.hideChated&&chat==='继续沟通'){node.style.display='none'}if(status&&chat){if(this.removeStatusList.includes(status)){node.style.display='none'}if(this.options.hideChated&&chat==='继续沟通'){node.style.display='none'}}}toggleDoms(){this.list.forEach((node)=>{this.toggleDom(node)})}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)});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;this.toggleDoms()});document.body.appendChild(container)}clear(){this.queque.length=0;this.list.length=0;this.startTime=null}init(){this.getList();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.toggleDoms();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()})();

源码版

javascript:(function () {
  'use strict';

  class ShowBossActiveTime {
    constructor(options) {
      this.startTime = null;/*记录是否是当前列表数据的循环,如果没查询完毕就重新触发的新的实例化,需要去停止旧的查询循环*/
      this.statusOptions = localStorage
        .getItem('bossActiveStatusList')
        ?.split(',').filter(t=>t.length) || [
        '半年前活跃',
        '近半年活跃',
        '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>&nbsp;&nbsp;&nbsp;&nbsp;
          <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('开始更新状态....,网站安全策略问题,更新会比较缓慢。');
      const startTime = new Date().getTime();
      this.startTime = startTime;
      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(startTime!==this.startTime){
          /*中断旧的循环查询*/ 
          return;
        }
      }
      if (this.queque.length === 0) {
        this.startTime = null;
        setTimeout(()=>{
          this.alertBox('查询完毕,更新即将完成');
        },1500);
      }
    }
    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);
                    this.toggleDom(node);
                  }
                );
              } 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);
                this.toggleDom(node);
              }
            }
          });
        };
      } 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);
              this.toggleDom(node);
            })
            .catch(async (error) => {
              /*请求被302临时重定向了,无法获取到数据,需要用iframe来获取了*/
              this.getStatusByIframe(link, index).then((text) => {
                if (text === '') {
                  text = '未知状态';
                }
                this.setText(node, text, chat);
                this.toggleDom(node);
              });
            });
        };
      }
    }
    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);

      /*监听是否是搜索列表页,不是就移除dom*/ 
      const listContainer = document.querySelector('#wrap');
      const listObserver = new MutationObserver((mutations) => {
        mutations.forEach((mutation) => {
          if (mutation.type === 'childList') {
            const wrapper = document.querySelector('.job-list-wrapper');
            const removeNode = document.querySelector("#removeFilterDataContainer");
            if(!wrapper&&removeNode){
              document.body.removeChild(removeNode);
              listObserver.disconnect();
              /*清除查询*/ 
              this.clear();
            }
          }
        });
      });
      listObserver.observe(listContainer, 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;
      }
    }
    toggleDom(node){
      const status = node.querySelector('.status')?.textContent;
      const chat = node.querySelector(this.options.chatElement).textContent;
      /*先显示全部*/ 
      node.style.display = 'block';
      /* 首先判断是否隐藏已沟通*/
      if (this.options.hideChated && chat === '继续沟通') {
        node.style.display = 'none';
      }
      /*状态数据已经获取了*/ 
      if (status && chat) {
        if (this.removeStatusList.includes(status)) {
          node.style.display = 'none';
        }
        if (this.options.hideChated && chat === '继续沟通') {
          node.style.display = 'none';
        }
      }
    }
    toggleDoms(){
      this.list.forEach((node) => {
        this.toggleDom(node);
      });
    }
    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);
      });

      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;
        this.toggleDoms();
      });

      document.body.appendChild(container);
    }
    clear(){
      this.queque.length = 0;
      this.list.length = 0;
      this.startTime = null;
    }

    init() {
      /*获取列表数据*/ 
      this.getList();
      /*先给在线的数据设置状态*/ 
      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.toggleDoms();
      /*请求数据,给不在线的设置状态*/ 
      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();
})();

有同学说要油猴版,又去看了下油猴怎么弄

油猴脚本的链接:showBossActiveTime 

git项目地址: GitHub - shrimpbighead/showBossActiveTime

### 回答1: 好的,下面是 C 语言期末考试的重点: 1. 数据类型:了解常用的数据类型,例如 int、float、char 等。 2. 运算符:熟悉 C 语言的常用运算符,例如算术运算符、关系运算符、逻辑运算符等。 3. 流程控制:掌握 C 语言的流程控制结构,例如 if、for、while 等。 4. 函数:学习如何使用函数,包括如何声明和调用函数。 5. 数组:了解数组的基本概念和使用方法。 6. 指针:掌握 C 语言的指针概念,例如指针变量、指针运算符等。 7. 字符串:学习如何使用字符串,例如字符串的定义、字符串的比较、字符串的拼接等。 这些内容是 C 语言期末考试的重点,请务必仔细学习,以便在考试中取得好成绩。 ### 回答2: C语言期末考试的重点主要包括以下内容: 1. 基本语法:了解C语言的基本语法规则,包括变量的定义和声明、数据类型、运算符、控制流程(如if语句、switch语句、循环语句等)、函数的定义和调用等。 2. 数组和指针:掌握数组和指针的使用方法,包括数组的定义、初始化、访问和遍历,指针的定义和使用、指针和数组的关系等。 3. 函数:了解函数的基本概念和作用,包括函数的定义、返回值、参数传递、递归等。 4. 文件操作:掌握文件的打开、关闭、读写等基本操作,了解文件指针和文件流的概念,能够进行文件的读写和文件的复制等操作。 5. 结构体和联合体:理解结构体和联合体的概念,能够定义和使用结构体和联合体,了解结构体和联合体的内存布局。 6. 动态内存管理:了解动态内存的概念和作用,能够使用malloc、calloc和free等函数对内存进行动态分配和释放。 7. 预处理器:了解预处理器的作用和使用方法,能够使用宏定义、条件编译等预处理指令。 8. 字符串处理:了解字符串的概念和常见的字符串操作函数,包括字符串的输入输出、比较、复制、连接、查找等。 在备考阶段,建议学生重点复习和练习以上内容,理解其原理和使用方法,同时通过做一些习题和实际编程练习来加深理解和提高编程能力。如果对某个特定的考点有疑问,可以多与老师和同学交流,以便更好地掌握。 ### 回答3: C语言期末考试的重点主要涵盖以下几个方面: 首先,掌握C语言的基本语法和语句结构。包括变量的声明和定义、常量的定义、运算符的使用、控制结构如顺序结构、选择结构和循环结构等。要熟练掌握这些基本知识,能够准确地写出C语言的基本程序段。 其次,了解数组和指针的使用。掌握数组的定义和初始化,以及数组的遍历和操作。同时,要了解指针的概念和使用方法,包括指针的声明和初始化、指针与数组的关系、指针的运算和指针的应用等。 此外,还需要熟悉函数的定义和调用。掌握函数的声明和定义、函数的参数传递和返回值,以及递归函数的使用。了解函数的作用和重要性,能够编写合适的函数来实现特定的功能。 最后,要熟悉C语言的文件操作和结构体。了解文件的打开和关闭、读写操作,以及文件指针的使用。同时,掌握结构体的定义和初始化,结构体的成员操作和结构体数组的使用。 在备考期末考试时,可以参考教材和课堂笔记,复习并巩固上述知识点。另外,可以多做一些相关的编程练习题,以提高对知识的理解和运用能力。加强实践,多写一些C语言的程序,提升对C语言的熟悉度和技能。 总之,期末考试的重点是掌握C语言的基本语法和语句结构、数组和指针的使用、函数的定义和调用,以及文件操作和结构体的应用。通过深入学习和实践,准备考试,相信你能取得好成绩!
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值