docs: 联网搜索服务架构方案全套(plan-final/design-arch/选型决策/整合导览/MCP文档/部署预设/联调手册) bench: 5 方案 + 代理 + 站点矩阵本机实测工程(无密钥) 部署目标:primary mgr1 先行测试(待批准后执行)
149 lines
5.5 KiB
Python
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()
|