93 lines
3.4 KiB
JavaScript
93 lines
3.4 KiB
JavaScript
(async () => {
|
|
const sleep = ms => new Promise(r => setTimeout(r, ms));
|
|
const out = { captured: [], clicks: [], err: null };
|
|
|
|
// 1) 在页面内挂钩 XHR + fetch,记录 mtop 响应原文
|
|
if (!window.__capHook) {
|
|
window.__cap = [];
|
|
window.__capHook = true;
|
|
const origOpen = XMLHttpRequest.prototype.open;
|
|
const origSend = XMLHttpRequest.prototype.send;
|
|
XMLHttpRequest.prototype.open = function (m, u, ...rest) {
|
|
this.__u = u; this.__m = m;
|
|
return origOpen.call(this, m, u, ...rest);
|
|
};
|
|
XMLHttpRequest.prototype.send = function (...a) {
|
|
this.addEventListener('load', function () {
|
|
try {
|
|
if (this.__u && /mtop|summary/i.test(this.__u)) {
|
|
window.__cap.push({ kind: 'xhr', url: String(this.__u), status: this.status, text: String(this.responseText || '') });
|
|
}
|
|
} catch (e) {}
|
|
});
|
|
return origSend.apply(this, a);
|
|
};
|
|
const origFetch = window.fetch;
|
|
window.fetch = async function (...a) {
|
|
const req = a[0];
|
|
const u = typeof req === 'string' ? req : (req && req.url) || '';
|
|
const r = await origFetch.apply(this, a);
|
|
try {
|
|
if (/mtop|summary/i.test(u)) {
|
|
const c = r.clone();
|
|
c.text().then(t => { if (/mtop|summary/i.test(u)) window.__cap.push({ kind: 'fetch', url: String(u), status: r.status, text: String(t || '') }); }).catch(() => {});
|
|
}
|
|
} catch (e) {}
|
|
return r;
|
|
};
|
|
}
|
|
|
|
// 2) 切时间范围,触发页面自己发请求
|
|
const clickRange = (label) => {
|
|
const res = { label, clicked: 0, skipped: 0 };
|
|
for (const g of document.querySelectorAll('.ant-radio-group')) {
|
|
const opts = Array.from(g.querySelectorAll('.ant-radio-wrapper, .ant-radio-button-wrapper'));
|
|
const t = opts.find(o => (o.innerText || '').trim() === label);
|
|
if (!t) continue;
|
|
if (/checked/.test(t.className) || t.querySelector('.ant-radio-checked')) { res.skipped++; continue; }
|
|
t.click(); res.clicked++;
|
|
}
|
|
return res;
|
|
};
|
|
|
|
window.__cap.length = 0;
|
|
out.clicks.push(clickRange('近7天'));
|
|
await sleep(5000);
|
|
const n7 = window.__cap.length;
|
|
out.clicks.push(clickRange('近30天'));
|
|
await sleep(6000);
|
|
const n30 = window.__cap.length;
|
|
out.clicks.push(clickRange('近1天'));
|
|
await sleep(5000);
|
|
|
|
// 3) 只保留 summary 相关、且能解析出 data 的
|
|
const seen = new Set();
|
|
for (const c of window.__cap) {
|
|
const key = c.url.slice(0, 160);
|
|
if (seen.has(key)) continue;
|
|
seen.add(key);
|
|
let api = '';
|
|
try { api = new URL(c.url, location.origin).searchParams.get('api') || ''; } catch (e) {}
|
|
let parsed = null;
|
|
try { parsed = JSON.parse(c.text); } catch (e) {}
|
|
out.captured.push({
|
|
kind: c.kind, status: c.status, api,
|
|
urlTail: c.url.slice(0, 200),
|
|
ret: parsed && parsed.ret ? parsed.ret : null,
|
|
dataKeys: parsed && parsed.data ? Object.keys(parsed.data) : null,
|
|
rawLen: c.text.length,
|
|
text: parsed ? null : c.text.slice(0, 300),
|
|
});
|
|
}
|
|
|
|
out.capTotal = window.__cap.length;
|
|
out.n7 = n7; out.n30 = n30;
|
|
|
|
// 4) 把完整原文也带出去(供离线解析)
|
|
out.rawBodies = window.__cap
|
|
.filter(c => { try { const p = JSON.parse(c.text); return p && p.data && p.data.data; } catch (e) { return false; } })
|
|
.map(c => ({ url: c.url.slice(0, 300), text: c.text.length > 300000 ? c.text.slice(0, 300000) : c.text }));
|
|
|
|
return out;
|
|
})()
|