#!/usr/bin/env python3 # -*- coding: utf-8 -*- """聚焦探测“生成过程”:招聘报表页点下载图标 -> 看参数窗内容 -> 确定 -> 观察 toast/任务中心出现与完成。""" import json, urllib.request, time D = "http://127.0.0.1:10086/command"; S = "2haohr" def call(a, args, t=90): b = json.dumps({"action": a, "args": args, "session": S}).encode() r = urllib.request.Request(D, data=b, headers={"Content-Type": "application/json"}) return json.loads(urllib.request.urlopen(r, timeout=t).read().decode()) def ev(c): try: return call("evaluate", {"code": c}).get("data", {}).get("value") except Exception as e: return "EXC:" + str(e)[:80] HOOK = r"""(()=>{window.__cap=window.__cap||[];if(!HTMLAnchorElement.prototype.__hk){const ac=HTMLAnchorElement.prototype.click; HTMLAnchorElement.prototype.click=function(){try{const h=this.href||'';if(h&&/-cdn\.2haohr|attname=|\.xlsx|\.xls|\.docx/i.test(h))window.__cap.push(h);}catch(e){}return ac.apply(this,arguments);};HTMLAnchorElement.prototype.__hk=1;}return 'ok';})()""" CLICK_ICON = r"""(()=>{const us=[...document.querySelectorAll('use')].filter(u=>(u.getAttribute('xlink:href')||u.getAttribute('href'))==='#icon-download'); for(const u of us){const b=u.closest('button,a,[role=button]');if(b){b.click();return 'ok';}}return 'none';})()""" # 参数窗全文 + 按钮列表 MODAL = r"""(()=>{const ms=[...document.querySelectorAll('[class*=modal],[class*=Modal],[role=dialog],[class*=dialog],[class*=drawer],[class*=Drawer]')]; const vis=ms.filter(m=>{const r=m.getBoundingClientRect();return r.width>200&&r.height>80&&getComputedStyle(m).display!=='none';}); if(!vis.length)return 'NO_MODAL';const m=vis[vis.length-1]; const btns=[...m.querySelectorAll('button,a')].map(b=>(b.innerText||'').trim()).filter(t=>t&&t.length<10); return JSON.stringify({text:(m.innerText||'').replace(/\n{2,}/g,'\n').slice(0,400),btns:[...new Set(btns)]});})()""" CONFIRM = r"""(()=>{const ms=[...document.querySelectorAll('[class*=modal],[class*=Modal],[role=dialog],[class*=dialog],[class*=drawer],[class*=Drawer]')]; const vis=ms.filter(m=>{const r=m.getBoundingClientRect();return r.width>200&&r.height>80&&getComputedStyle(m).display!=='none';}); if(!vis.length)return 'NO_MODAL';const m=vis[vis.length-1]; for(const t of ['确定','确认','下载','导出','生成']){const b=[...m.querySelectorAll('button,a')].find(x=>(x.innerText||'').trim()===t&&x.getBoundingClientRect().width>0);if(b){b.click();return 'click:'+t;}}return 'noconfirm';})()""" TOAST = r"""(()=>{const a=[];document.querySelectorAll('[class*=message],[class*=Message],[class*=toast],[class*=notify],[class*=Notification]').forEach(el=>{const t=(el.innerText||'').trim();if(t&&t.length<60&&el.getBoundingClientRect().width>0)a.push(t);});return JSON.stringify([...new Set(a)]);})()""" TC = r"""(()=>{const tc=document.querySelector('[class*=taskCenter]');if(!tc)return 'NO_TC'; const dls=[...tc.querySelectorAll('a')].filter(a=>(a.innerText||'').trim()==='下载'); return JSON.stringify({dl:dls.length,text:(tc.innerText||'').replace(/\n{2,}/g,'\n').slice(0,300)});})()""" def main(): call("find_tab", {"url": "2haohr.com"}) call("navigate", {"url": "https://2haohr.com/recruit/statistics/recruit-report", "newTab": False}) time.sleep(7) ev(HOOK) print("icon click:", ev(CLICK_ICON)) time.sleep(2) print("MODAL:", ev(MODAL)) print("confirm:", ev(CONFIRM)) # 观察生成过程 for i in range(10): time.sleep(3) cap = ev("(window.__cap&&window.__cap.length)||0") print(" t+%ds cap=%s toast=%s" % (3*(i+1), cap, ev(TOAST))) if isinstance(cap, int) and cap > 0: print(" >>> 捕获直链!"); break print("TASK_CENTER:", ev(TC)) if __name__ == "__main__": main()