'use strict'; /* 对比两次 analyze 请求体,定位缓存指纹不稳定的原因 */ const BASE = process.env.BASE || 'http://127.0.0.1:8788'; const AMAP = process.env.AMAP_KEY || ''; const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); class CDP { constructor(ws) { this.ws = ws; this.id = 0; this.waits = new Map(); } static async connect(url) { const ws = new WebSocket(url); await new Promise((res, rej) => { ws.onopen = res; ws.onerror = rej; }); const c = new CDP(ws); ws.onmessage = (e) => { const m = JSON.parse(e.data); if (m.id && c.waits.has(m.id)) { c.waits.get(m.id)(m); c.waits.delete(m.id); } }; return c; } send(method, params = {}, sessionId) { const id = ++this.id; return new Promise((res) => { this.waits.set(id, res); this.ws.send(JSON.stringify({ id, method, params, sessionId })); }); } } (async () => { const { webSocketDebuggerUrl } = await (await fetch('http://127.0.0.1:9333/json/version')).json(); const browser = await CDP.connect(webSocketDebuggerUrl); const { result: { targetId } } = await browser.send('Target.createTarget', { url: 'about:blank' }); const { result: { sessionId } } = await browser.send('Target.attachToTarget', { targetId, flatten: true }); const S = (m, p) => browser.send(m, p, sessionId); await S('Page.enable'); await S('Runtime.enable'); const evalJs = async (expr) => { const r = await S('Runtime.evaluate', { expression: expr, awaitPromise: true, returnByValue: true }); if (r.result?.exceptionDetails) throw new Error(JSON.stringify(r.result.exceptionDetails).slice(0, 400)); return r.result?.result?.value; }; await S('Page.navigate', { url: BASE }); await sleep(2500); if (AMAP) { await evalJs(`(() => { const raw = JSON.parse(localStorage.getItem('tripsense.ai') || '{}'); raw.amapKey = ${JSON.stringify(AMAP)}; localStorage.setItem('tripsense.ai', JSON.stringify(raw)); return true; })()`); await S('Page.reload'); await sleep(2500); } // 拦截 fetch,记录 /api/analyze 的请求体 await evalJs(`(() => { window.__bodies = []; const of = window.fetch; window.fetch = async function (u, o) { if (String(u).includes('/api/analyze') && o && o.body) window.__bodies.push(o.body); return of.apply(this, arguments); }; return true; })()`); await evalJs(`(() => { const el = document.querySelector('#originInput'); el.value = '柳州'; el.dispatchEvent(new Event('input', { bubbles: true })); return true; })()`); for (let i = 0; i < 20; i++) { await sleep(1000); const ok = await evalJs(`(() => { const it = document.querySelector('#suggestBox .suggest-item'); if (it && !document.querySelector('#suggestBox').classList.contains('hidden')) { it.click(); return true; } return false; })()`); if (ok) break; } for (let i = 1; i <= 2; i++) { await evalJs(`(() => { const b = document.querySelector('#analyzeBtn'); if (b) b.click(); return true; })()`); for (let k = 0; k < 40; k++) { await sleep(500); const n = await evalJs(`document.querySelectorAll('.dest-card').length`); if (n) break; } await sleep(1500); console.log(`run ${i} done, cards =`, await evalJs(`document.querySelectorAll('.dest-card').length`)); } const bodies = await evalJs(`window.__bodies`); console.log('\n=== captured analyze bodies ==='); (bodies || []).forEach((b, i) => console.log(`[${i}]`, b)); if ((bodies || []).length >= 2) { console.log('\nidentical =', bodies[0] === bodies[1]); } browser.ws.close(); process.exit(0); })().catch((e) => { console.error('FAIL', e.message); process.exit(1); });