71 lines
3.4 KiB
Python
71 lines
3.4 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""探测任务中心(taskCenter):结构、任务项状态、下载链路。并测试整表页的导出图标(hover tooltip)。"""
|
|
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, timeout=120):
|
|
try:
|
|
return call("evaluate", {"code": code}, timeout).get("data", {}).get("value")
|
|
except Exception as e:
|
|
return "EXC:" + str(e)[:80]
|
|
|
|
HOOK = r"""(()=>{window.__cap=[];const ac=HTMLAnchorElement.prototype.click;
|
|
HTMLAnchorElement.prototype.click=function(){try{const h=this.href||'';if(h&&/prv-cdn|attname=|\.xlsx|\.xls|\.docx|\.doc|\.zip/i.test(h))window.__cap.push(h);}catch(e){}return ac.apply(this,arguments);};return 'ok';})()"""
|
|
|
|
# 读取任务中心:定位 taskCenter 容器,列出每个任务项(名称/状态/是否有下载)
|
|
TASKS = r"""(()=>{
|
|
const tc=document.querySelector('[class*=taskCenter]');
|
|
if(!tc)return 'NO_TASKCENTER';
|
|
const items=[];
|
|
// 任务项通常是含 info_ 名称 + right_ 状态 的行
|
|
tc.querySelectorAll('[class*=info_]').forEach(info=>{
|
|
const row=info.closest('[class*=item],li,tr')||info.parentElement;
|
|
const name=(info.innerText||'').replace(/\n+/g,' ').trim().slice(0,40);
|
|
let dl='';const a=row&&row.querySelector('a');
|
|
const stat=row?(row.innerText||'').replace(/\n+/g,'|').slice(0,40):'';
|
|
items.push({name:name,row:stat});
|
|
});
|
|
return JSON.stringify({open:getComputedStyle(tc).display,cnt:items.length,items:items.slice(0,10)});
|
|
})()"""
|
|
|
|
# 点击任务中心里第 idx 个“下载”链接
|
|
CLICK_TASK_DL = r"""(function(idx){
|
|
const tc=document.querySelector('[class*=taskCenter]');if(!tc)return 'NO_TC';
|
|
const dls=[...tc.querySelectorAll('a')].filter(a=>(a.innerText||'').trim()==='下载');
|
|
if(idx>=dls.length)return 'IDX_OOB len='+dls.length;
|
|
dls[idx].click();return 'clicked '+idx+'/'+dls.length;
|
|
})(%d)"""
|
|
|
|
FETCH_LAST = 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]):('f_'+Date.now());
|
|
return JSON.stringify({size:s.length,name:name});}catch(e){return 'EX '+e.message;}})()"""
|
|
|
|
def main():
|
|
call("find_tab", {"url": "2haohr.com"})
|
|
print("== 当前任务中心 ==")
|
|
print(ev(TASKS))
|
|
ev(HOOK)
|
|
# 实测抓第一个任务下载
|
|
print("click:", ev(CLICK_TASK_DL % 0))
|
|
time.sleep(2.5)
|
|
meta = ev(FETCH_LAST)
|
|
print("fetch:", meta)
|
|
if isinstance(meta, str) and meta.startswith("{"):
|
|
info = json.loads(meta); data = base64.b64decode(ev("window.__b64||''"))
|
|
os.makedirs("downloads/_test", exist_ok=True)
|
|
out = "downloads/_test/task_" + info["name"]
|
|
open(out, "wb").write(data); print("落盘:", out, len(data))
|
|
|
|
if __name__ == "__main__":
|
|
main()
|