#!/usr/bin/env python3 """CDP v3: 深度诊断前端白屏问题 — 检查 DOM、网络、JS 模块加载""" import json, time, base64, urllib.request, os # Step 1: 打开新页面 print("=== Step 1: 导航到前端页面 ===") req = urllib.request.Request("http://127.0.0.1:9225/json/new?url=http://localhost:5199/", method="PUT") resp = urllib.request.urlopen(req, timeout=10) page_data = json.loads(resp.read()) page_id = page_data.get("id","") ws_url = page_data.get("webSocketDebuggerUrl","") print(f" Page ID: {page_id}") print(f" WS URL: {ws_url[:80]}") from websocket import create_connection ws = create_connection(ws_url, timeout=10) def cdp(method, params=None, msg_id=1): ws.send(json.dumps({"id": msg_id, "method": method, "params": params or {}})) def recv_all(timeout=3): ws.settimeout(timeout) msgs = [] try: while True: msgs.append(ws.recv()) except: pass return msgs def find_result(msgs, msg_id): for m in msgs: try: d = json.loads(m) if d.get("id") == msg_id: return d.get("result",{}) except: pass return None # Step 2: 启用所有 domains print("\n=== Step 2: 启用所有 domains ===") cdp("Page.enable", {}, 1) cdp("Network.enable", {}, 2) cdp("Runtime.enable", {}, 3) cdp("Log.enable", {}, 4) cdp("DOM.enable", {}, 5) recv_all(1) # Step 3: 重新 navigate 以捕获网络事件 print("\n=== Step 3: 重新导航 ===") cdp("Page.navigate", {"url": "http://localhost:5199/"}, 10) time.sleep(3) # 收集在此期间的所有消息 print(" 收集网络/运行时事件...") all_msgs = recv_all(5) # 分析网络事件 print("\n=== Step 4: 网络请求分析 ===") requests = {} for m in all_msgs: try: d = json.loads(m) except: continue method = d.get("method","") params = d.get("params",{}) if method == "Network.requestWillBeSent": req_info = params.get("request", {}) url = req_info.get("url","") req_id = params.get("requestId","") rtype = params.get("type","") requests[req_id] = {"url": url, "type": rtype, "status": "pending"} elif method == "Network.responseReceived": req_id = params.get("requestId","") resp = params.get("response",{}) status = resp.get("status",0) mime = resp.get("mimeType","") if req_id in requests: requests[req_id]["status"] = status requests[req_id]["mime"] = mime elif method == "Network.loadingFailed": req_id = params.get("requestId","") err = params.get("errorText","") if req_id in requests: requests[req_id]["status"] = "FAILED" requests[req_id]["error"] = err elif method == "Runtime.exceptionThrown": exc = params.get("exceptionDetails",{}) print(f" [EXCEPTION] {exc.get('text','')} at {exc.get('url','')}:{exc.get('lineNumber','')}") elif method == "Log.entryAdded": entry = params.get("entry",{}) print(f" [CONSOLE:{entry.get('level','log')}] {entry.get('text','')[:200]}") elif method == "Runtime.consoleAPICalled": args = params.get("args",[]) msg_type = params.get("type","log") texts = [] for a in args: t = a.get("value","") or a.get("description","") texts.append(str(t)[:150]) print(f" [CONSOLE:{msg_type}] {' '.join(texts)}") print(f"\n Total network requests: {len(requests)}") for rid, info in requests.items(): status_str = str(info.get("status","?")) type_str = info.get("type","?") url_short = info.get("url","")[-80:] error_str = f" ERROR={info.get('error','')}" if info.get("error") else "" print(f" [{type_str}] {status_str} {url_short}{error_str}") # Step 5: 运行时评估 - 深度检查 print("\n=== Step 5: 运行时深度评估 ===") checks = [ ("window.location.href", "window.location.href"), ("document.readyState", "document.readyState"), ("document.title", "document.title"), ("root element", "document.getElementById('root') ? 'EXISTS' : 'NULL'"), ("body innerHTML length", "document.body ? document.body.innerHTML.length : -1"), ("body children count", "document.body ? document.body.children.length : -1"), ("head children count", "document.head ? document.head.children.length : -1"), ("all scripts", "Array.from(document.querySelectorAll('script')).map(s => ({src:s.src,type:s.type,async:s.async,defer:s.defer})).slice(0,5)"), ("React DOM check", "typeof React !== 'undefined' ? 'React global found' : (document.querySelector('#root') ? 'root exists but no React global' : 'root missing')"), ("SW registration check", "'serviceWorker' in navigator ? 'SW API available' : 'NO SW API'"), ("localStorage token", "localStorage.getItem('token') || 'no token'"), ] for idx, (label, expr) in enumerate(checks): msg_id = 100 + idx cdp("Runtime.evaluate", {"expression": expr, "returnByValue": True}, msg_id) recv_msgs = recv_all(2) r = find_result(recv_msgs, msg_id) if r: val = r.get("result",{}).get("value","?") # 处理 object 类型 if isinstance(val, dict) and "objectId" in r.get("result",{}): val = r["result"].get("description","[object]") err = r.get("result",{}).get("description","") or "" print(f" {label}: {val}") if r.get("result",{}).get("type") == "object": # Try to get properties obj_id = r["result"].get("objectId","") if obj_id: cdp("Runtime.getProperties", {"objectId": obj_id, "ownProperties": True}, 900 + idx) prop_msgs = recv_all(2) prop_r = find_result(prop_msgs, 900 + idx) if prop_r: for prop in prop_r.get("result",[]): v = prop.get("value",{}) print(f" .{prop.get('name','?')} = {v.get('value', v.get('description','?'))}") else: print(f" {label}: NO RESULT") # Step 6: 截图 print("\n=== Step 6: 截图 ===") cdp("Page.captureScreenshot", {"format": "png", "captureBeyondViewport": True}, 20) recv_msgs = recv_all(5) r = find_result(recv_msgs, 20) if r and r.get("data"): img = base64.b64decode(r["data"]) fp = "/tmp/cyrene_screenshot_round12_v3.png" with open(fp, "wb") as f: f.write(img) print(f" Screenshot: {len(img)} bytes -> {fp}") else: print(f" Screenshot failed: {str(r)[:200]}") # Step 7: 检查是否有 JS 异常 print("\n=== Step 7: 最终 JS 异常检查 ===") ws.settimeout(1) has_exception = False for i in range(5): try: d = json.loads(ws.recv()) if d.get("method") == "Runtime.exceptionThrown": exc = d["params"]["exceptionDetails"] print(f" [EXCEPTION] text={exc.get('text','')}") print(f" url={exc.get('url','')}") print(f" line={exc.get('lineNumber','')} col={exc.get('columnNumber','')}") stack = exc.get("stackTrace",{}) for frame in stack.get("callFrames",[]): print(f" at {frame.get('functionName','')} {frame.get('url','')}:{frame.get('lineNumber','')}") has_exception = True except: break if not has_exception: print(" No exceptions caught") ws.close() print("\n[DONE v3]")