#!/usr/bin/env python3 # -*- coding: utf-8 -*- """干净验证:报表页点下载 -> 捕获CDN直链 -> 页面内同步XHR取字节 -> base64回传 -> 落盘。""" import json, urllib.request, base64, time, os D = "http://127.0.0.1:10086/command"; S = "2haohr" def call(a, args, timeout=120): 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=timeout).read().decode()) def ev(code): return call("evaluate", {"code": code}).get("data", {}).get("value") # 单一、幂等的 hook(navigate 后页面重载,hook 会被清) HOOK = r"""(()=>{ if(window.__H)return 'already'; window.__H=1; window.__cap=[]; const ac=HTMLAnchorElement.prototype.click; HTMLAnchorElement.prototype.click=function(){ try{const h=this.href||'';const d=this.getAttribute('download')||''; if(h && (/prv-cdn|attname=|\.xlsx|\.xls|\.docx|\.doc|\.zip|\.pdf/i.test(h)||d)) window.__cap.push(h);}catch(e){} return ac.apply(this,arguments); }; return 'hooked'; })()""" CLICK_DL = r"""(()=>{const cand=['直接下载','下载','生成excel','导出Excel','导出']; for(const t of cand){const b=[...document.querySelectorAll('button,a,[role=button]')] .find(x=>(x.innerText||'').trim()===t && x.getBoundingClientRect().width>0); if(b){b.click();return t;}}return 'no-btn';})()""" # 弹窗里确认导出(选择部门后 生成excel/确定/下载) CONFIRM = r"""(()=>{const cand=['生成excel','确定','下载','导出','确认']; const ms=[...document.querySelectorAll('[class*=modal],[class*=Modal],[role=dialog],[class*=dialog],[class*=drawer]')]; for(const m of ms){const r=m.getBoundingClientRect(); if(r.width>200&&r.height>100&&getComputedStyle(m).display!=='none'){ for(const t of cand){const b=[...m.querySelectorAll('button,a')] .find(x=>(x.innerText||'').trim()===t); if(b){b.click();return 'modal:'+t;}}}}return 'no-modal';})()""" FETCH_B64 = r"""(()=>{try{ if(!window.__cap.length)return 'NO_HREF'; const u=window.__cap[window.__cap.length-1]; const x=new XMLHttpRequest();x.open('GET',u,false); x.overrideMimeType('text/plain;charset=x-user-defined');x.send(); if(x.status!==200)return 'HTTP'+x.status; const s=x.responseText;let out='';const CH=8192; for(let i=0;i{let n=0;document.querySelectorAll('button,a,[role=button]').forEach(x=>{const t=(x.innerText||'').trim();if(['直接下载','下载','生成excel','导出Excel','导出'].includes(t)&&x.getBoundingClientRect().width>0)n++;});return n;})()""" for i in range(15): time.sleep(2) c = ev(COUNT) print(" wait btn count=", c) if isinstance(c, int) and c > 0: break print("hook:", ev(HOOK)) print("click:", ev(CLICK_DL)) time.sleep(2.5) print("confirm:", ev(CONFIRM)) time.sleep(2.5) meta = ev(FETCH_B64) print("fetch:", meta) if isinstance(meta, str) and meta.startswith("{"): info = json.loads(meta) b64 = ev("window.__b64") data = base64.b64decode(b64) os.makedirs("downloads/_test", exist_ok=True) out = "downloads/_test/probe_" + info["name"] open(out, "wb").write(data) print("落盘:", out, len(data), "bytes") if __name__ == "__main__": main()