import './wb-legacy-disabled.mjs' /** * 完整采集对标外围结构:侧栏(品牌/导航/分组/账号)、搜索、通知、设置入口。 * * 用法:node scripts/wb-shell.mjs [outJson] */ import { writeFile } from 'node:fs/promises' const port = Number(process.argv[2] ?? 9223) const outJson = process.argv[3] ?? null const PROPS = [ 'display', 'flex-direction', 'align-items', 'justify-content', 'width', 'height', 'min-height', 'padding-top', 'padding-right', 'padding-bottom', 'padding-left', 'margin-top', 'margin-bottom', 'gap', 'background-color', 'color', 'border-top-width', 'border-top-color', 'border-radius', 'font-size', 'font-weight', 'line-height', 'opacity', 'position' ] async function main() { const list = await (await fetch(`http://127.0.0.1:${port}/json/list`)).json() const page = list.filter((t) => t.type === 'page')[0] if (!page) throw new Error('未找到页面') const ws = new WebSocket(page.webSocketDebuggerUrl) await new Promise((r, j) => { const t = setTimeout(() => j(new Error('连接超时')), 8000) ws.addEventListener('open', () => { clearTimeout(t) r() }) ws.addEventListener('error', () => { clearTimeout(t) j(new Error('连接失败')) }) }) const send = (method, params = {}) => new Promise((res, rej) => { const id = Math.floor(Math.random() * 1e9) const timer = setTimeout(() => rej(new Error(`超时 ${method}`)), 25000) const h = (ev) => { const m = JSON.parse(ev.data) if (m.id === id) { clearTimeout(timer) ws.removeEventListener('message', h) res(m.result) } } ws.addEventListener('message', h) ws.send(JSON.stringify({ id, method, params })) }) const expr = `(() => { const PROPS = ${JSON.stringify(PROPS)}; const clean = (v) => (v == null ? '' : String(v).replace(/\\s+/g, ' ').trim()); const picked = (el) => { const cs = getComputedStyle(el); const o = {}; for (const p of PROPS) { const v = clean(cs.getPropertyValue(p)); if (v && v !== 'normal' && v !== 'auto' && v !== 'none' && v !== '0px' && v !== 'rgba(0, 0, 0, 0)') o[p] = v; } return o; }; const rect = (el) => { const r = el.getBoundingClientRect(); return [Math.round(r.x), Math.round(r.y), Math.round(r.width), Math.round(r.height)]; }; // 1) 侧栏完整子树(含文字节点) const side = document.querySelector('.conversation-sidebar') || document.querySelector('[class*="sidebar"]'); const sidebar = []; if (side) { const walk = (el, depth) => { if (depth > 12) return; const r = el.getBoundingClientRect(); if (r.width < 1 || r.height < 1) return; const kids = [...el.children]; const ownText = kids.length === 0 ? clean(el.textContent).slice(0, 60) : ''; sidebar.push({ d: depth, tag: el.tagName.toLowerCase(), cls: clean(el.className).slice(0, 90), text: ownText, rect: rect(el), st: picked(el) }); kids.forEach((c) => walk(c, depth + 1)); }; walk(side, 0); } // 2) 全局搜外围相关元素(搜索/通知/账号/设置) const keyword = /search|notif|account|avatar|user|profile|setting|login|inbox|message|bell/i; const found = []; document.querySelectorAll('[class]').forEach((el) => { if (typeof el.className !== 'string') return; if (!keyword.test(el.className)) return; const r = el.getBoundingClientRect(); if (r.width < 8 || r.height < 8) return; found.push({ cls: clean(el.className).slice(0, 100), rect: rect(el), text: clean(el.textContent).slice(0, 60), st: picked(el) }); }); return JSON.stringify({ viewport: { w: innerWidth, h: innerHeight }, sidebar, found: found.slice(0, 60) }); })()` const r = await send('Runtime.evaluate', { expression: expr, returnByValue: true }) const data = JSON.parse(r.result.value) console.log(`viewport ${data.viewport.w}x${data.viewport.h}`) console.log(`\n===== 侧栏子树(${data.sidebar.length} 节点)=====`) for (const n of data.sidebar) { const cls = n.cls ? '.' + n.cls.split(/\s+/).slice(0, 2).join('.') : '' const txt = n.text ? ` "${n.text}"` : '' console.log(`${' '.repeat(n.d)}${n.tag}${cls} [${n.rect.join(',')}]${txt}`) const keys = Object.keys(n.st) if (keys.length) console.log(`${' '.repeat(n.d)} ${JSON.stringify(n.st)}`) } console.log(`\n===== 外围相关元素(${data.found.length})=====`) for (const f of data.found) { console.log(` .${f.cls.split(/\s+/).slice(0, 2).join('.')} [${f.rect.join(',')}] "${f.text}"`) } if (outJson) { await writeFile(outJson, JSON.stringify(data, null, 2), 'utf8') console.log(`\n已写出 ${outJson}`) } ws.close() } main().catch((e) => { console.error('失败:', e.message) process.exit(1) })