first commit

This commit is contained in:
Michelle Zan
2026-09-03 15:35:23 +08:00
commit 9b26161bcf
510 changed files with 29402 additions and 0 deletions
+86
View File
@@ -0,0 +1,86 @@
#!/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<s.length;i+=CH){let c='';const e=Math.min(i+CH,s.length);
for(let j=i;j<e;j++)c+=String.fromCharCode(s.charCodeAt(j)&0xff);out+=c;}
window.__b64=btoa(out);
const m=u.match(/attname=([^&]+)/);let name=m?decodeURIComponent(m[1]):'file';
return JSON.stringify({size:s.length,name:name,url:u.slice(0,60)});
}catch(e){return 'EX '+e.message;}})()"""
def main():
call("find_tab", {"url": "2haohr.com"})
call("navigate", {"url": "https://2haohr.com/personnel/employee/personnel-report/home", "newTab": False})
# 轮询等下载按钮出现
COUNT = r"""(()=>{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()