onesvm-browser-server/bench/site-matrix/reclassify.py
chii 983259836d chore: init workspace with onesvm-dev-md + casa-commander
docs: 联网搜索服务架构方案全套(plan-final/design-arch/选型决策/整合导览/MCP文档/部署预设/联调手册)
bench: 5 方案 + 代理 + 站点矩阵本机实测工程(无密钥)
部署目标:primary mgr1 先行测试(待批准后执行)
2026-09-01 15:19:52 +08:00

149 lines
5.5 KiB
Python

#!/usr/bin/env python3
"""Recompute intercept/title_ok/extractable from recorded fields. No re-fetch, no secrets."""
from __future__ import annotations
import json
from pathlib import Path
from classify import BLOCK_TITLE
from urllib.parse import urlparse
ROOT = Path(__file__).resolve().parent
RAW = ROOT / "raw"
TARGETS = json.loads((ROOT / "targets.json").read_text(encoding="utf-8"))
SITES = {s["slug"]: s for s in TARGETS["sites"]}
def classify(row: dict) -> str:
title = (row.get("title") or "").strip()
text = row.get("text_head") or ""
text_len = int(row.get("text_len") or 0)
status = int(row.get("http_status") or 0)
final = row.get("final_url") or ""
start = row.get("used_url") or row.get("start_url") or ""
hops = len(row.get("redirect_chain") or [])
tl = title.lower()
text_l = text.lower()
if tl in {"just a moment...", "attention required! | cloudflare"} or BLOCK_TITLE.search(title):
return "cloudflare"
if title == "百度安全验证" or "请向右滑动完成拼图" in text or "请完成下方验证" in text:
return "captcha"
if "you've been blocked by network security" in text_l:
return "waf"
if "click the button below to continue shopping" in text_l:
return "waf"
if "正在进行安全检测" in text:
return "captcha"
if "sina visitor system" in tl or "passport.weibo.com" in final:
return "redirect"
if status == 403 and text_len < 80 and ("zhihu.com" in start or "zhihu.com" in final):
return "waf"
if status == 403 and text_len < 80:
return "waf"
if status == 404:
return "empty"
if text_len < 500 and any(
x in text_l for x in ("continue with google", "continue with apple", "already have an account?")
):
return "redirect"
# substantial real page
if status == 200 and text_len >= 400 and title and not BLOCK_TITLE.search(title):
sp = urlparse(start).path or ""
fp = urlparse(final).path or ""
if "/products/" in sp and fp and sp.rstrip("/") != fp.rstrip("/"):
return "redirect"
return "none"
if hops and "passport" in final:
return "redirect"
if hops and "/products/" in (urlparse(start).path or "") and urlparse(start).path != urlparse(final).path:
return "redirect"
if status == 200 and text_len < 80:
return "empty"
if status == 0:
return "empty"
if status >= 400:
return "waf" if status in (401, 403, 406, 429, 451, 503) else "empty"
return "none"
def title_ok(row: dict, intercept: str) -> bool:
if intercept in {"cloudflare", "waf", "captcha"}:
return False
title = (row.get("title") or "").strip()
if not title or BLOCK_TITLE.search(title):
return False
site = SITES.get(row.get("slug") or "")
needles = (site or {}).get("title_needles") or []
blob = (title + "\n" + (row.get("text_head") or "")[:1500]).lower()
if any(n.lower() in blob for n in needles):
return True
if title.lower().strip() in {"x", "x.com"}:
return True
if any(x in title.lower() for x in ("visitor system", "passport", "安全验证", "just a moment")):
return False
# real headline on a non-block page
if intercept == "none" and len(title) >= 8:
return True
return False
def extractable(row: dict, intercept: str, text_len: int, tok: bool) -> bool:
if intercept in {"cloudflare", "waf", "captcha", "empty"}:
return False
text_l = (row.get("text_head") or "").lower()
if any(x in text_l for x in ("continue with google", "already have an account?", "sina visitor")):
return False
if intercept == "redirect" and text_len < 400:
return False
if text_len >= 200:
return True
return False
def apply_one(path: Path) -> dict:
row = json.loads(path.read_text(encoding="utf-8"))
intercept = classify(row)
tok = title_ok(row, intercept)
row["intercept"] = intercept
row["title_ok"] = bool(tok)
row["extractable"] = extractable(row, intercept, int(row.get("text_len") or 0), tok)
path.write_text(json.dumps(row, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
return row
def write_jsonl(prefix: str, group: str, rows: list[dict]) -> None:
rows = sorted(rows, key=lambda r: int(r["id"]))
p = RAW / f"{prefix}-{group}.jsonl"
p.write_text("".join(json.dumps(r, ensure_ascii=False) + "\n" for r in rows), encoding="utf-8")
def main() -> None:
http_f, http_d, lp_f, lp_d = [], [], [], []
for p in sorted(RAW.glob("http-*.json")):
if ".listing." in p.name or p.name.endswith(".container.log"):
continue
row = apply_one(p)
(http_f if row.get("group") == "foreign" else http_d).append(row)
for p in sorted(RAW.glob("lp-*.json")):
if ".listing." in p.name or p.name.endswith(".excerpt.json"):
continue
row = apply_one(p)
(lp_f if row.get("group") == "foreign" else lp_d).append(row)
write_jsonl("http", "foreign", http_f)
write_jsonl("http", "domestic", http_d)
write_jsonl("lp", "foreign", lp_f)
write_jsonl("lp", "domestic", lp_d)
print(f"reclassified http_f={len(http_f)} http_d={len(http_d)} lp_f={len(lp_f)} lp_d={len(lp_d)}")
for r in http_f + http_d + lp_f + lp_d:
print(
f" {r['channel'][:4]} {r['id']:02d} {r['slug']:12} "
f"st={r.get('http_status')} {r['intercept']:10} ext={r['extractable']} "
f"tok={r['title_ok']} n={r.get('text_len')}"
)
if __name__ == "__main__":
main()