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
+107
View File
@@ -0,0 +1,107 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
遍历全部顶导航模块, 映射每个模块的侧边栏功能结构。
含随机 5-15s 点击间隔(反爬)。结果写入 db/menu_map.json, 进度写 db/map_progress.log
"""
import json, time, random, os, urllib.request
DAEMON = "http://127.0.0.1:10086/command"
SESSION = "2haohr"
BASE = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
OUT = os.path.join(BASE, "db", "menu_map.json")
LOG = os.path.join(BASE, "db", "map_progress.log")
# (模块名, 是否在"更多"下拉里, 备注)
MODULES = [
("工作台", 0), ("人事", 0), ("组织", 0), ("招聘", 0), ("考勤假期", 0), ("薪酬", 0),
("审批", 1), ("培训学习", 1), ("绩效", 1), ("社保公积金", 1), ("行政管理", 1),
("电子合同", 1), ("背景调查", 1), ("人才测评", 1), ("员工福利", 1), ("人事仪表盘", 1),
("第三方对接", 1), ("培训商城", 1), ("短信发送", 1), ("电子工资条", 1), ("智能薪酬", 1),
("个税对接", 1), ("AI员工助手", 1), ("应用管理", 1),
]
def call(action, args):
body = json.dumps({"action": action, "args": args, "session": SESSION}).encode()
req = urllib.request.Request(DAEMON, data=body, headers={"Content-Type": "application/json"})
with urllib.request.urlopen(req, timeout=45) as resp:
return json.loads(resp.read().decode())
def ev(code):
try:
return call("evaluate", {"code": code}).get("data", {}).get("value")
except Exception as e:
return "ERR:" + str(e)
CLICK_TOP = """
(()=>{const name=%s;
const els=[...document.querySelectorAll("a,span,div,li")].filter(e=>{
const t=(e.innerText||"").trim();const r=e.getBoundingClientRect();
return t===name && r.top<60 && r.width>8 && r.width<160;});
if(els.length){els[0].click();return "top-clicked";}return "not-found";})()
"""
OPEN_MORE = """
(()=>{const els=[...document.querySelectorAll("a,span,div,li")].filter(e=>{
const t=(e.innerText||"").trim();const r=e.getBoundingClientRect();
return t==="更多" && r.top<60 && r.width>8 && r.width<160;});
if(!els.length)return "no-more"; const el=els[0];
["pointerover","mouseover","mouseenter","pointerenter"].forEach(tp=>el.dispatchEvent(new MouseEvent(tp,{bubbles:true,cancelable:true,view:window})));
el.click(); return "more-hover";})()
"""
CLICK_ANY = """
(()=>{const name=%s;
const els=[...document.querySelectorAll("a,span,div,li")].filter(e=>(e.innerText||"").trim()===name && e.getBoundingClientRect().width>=0);
if(els.length){els[els.length-1].click();return "clicked";}return "not-found";})()
"""
EXTRACT = r"""
(()=>{
const root=document.querySelector("[class*=leftMenu]")||document.querySelector("[class*=menu_]");
const groups=[]; let cur={title:"",items:[]}; groups.push(cur); const seen=new Set();
if(root){const walk=(el)=>{for(const c of el.children){const cls=(c.className||"").toString();
if(/nameTitle/.test(cls)&&!c.closest("a")){const t=(c.innerText||"").trim();if(t){cur={title:t,items:[]};groups.push(cur);}}
if(c.tagName==="A"){const h=c.getAttribute("href")||"";const t=(c.innerText||"").trim().replace(/\s+/g," ");
if(h&&h.length>1&&t&&!seen.has(h)){seen.add(h);cur.items.push({name:t,href:h});}}
walk(c);}}; walk(root);}
return JSON.stringify({loc:location.href,groups:groups.filter(g=>g.items.length)});
})()
"""
def log(msg):
line = time.strftime("%H:%M:%S ") + msg
print(line, flush=True)
with open(LOG, "a") as f:
f.write(line + "\n")
def main():
results = {}
if os.path.exists(OUT):
results = json.load(open(OUT))
for i, (mod, in_more) in enumerate(MODULES):
if mod in results and results[mod].get("groups"):
log(f"skip {mod} (already mapped)"); continue
delay = random.uniform(5, 15)
log(f"[{i+1}/{len(MODULES)}] wait {delay:.1f}s -> {mod}")
time.sleep(delay)
name_js = json.dumps(mod, ensure_ascii=False)
if in_more:
ev(OPEN_MORE); time.sleep(1.5); r = ev(CLICK_ANY % name_js)
else:
r = ev(CLICK_TOP % name_js)
if r == "not-found":
ev(OPEN_MORE); time.sleep(1.5); r = ev(CLICK_ANY % name_js)
time.sleep(3.2)
data = ev(EXTRACT)
try:
parsed = json.loads(data)
except Exception:
parsed = {"loc": "", "groups": [], "raw": str(data)[:200]}
parsed["in_more"] = in_more
parsed["click"] = r
results[mod] = parsed
n = sum(len(g["items"]) for g in parsed.get("groups", []))
log(f" {mod}: loc={parsed.get('loc','')} groups={len(parsed.get('groups',[]))} items={n} click={r}")
json.dump(results, open(OUT, "w"), ensure_ascii=False, indent=1)
log("DONE all modules")
if __name__ == "__main__":
main()