// 解析已抓取的 mtop 响应,输出结构与关键字段 import fs from 'node:fs'; import path from 'node:path'; const dir = path.resolve(process.argv[2] || '.cdp/out/api'); const files = fs.readdirSync(dir).filter(f => f.endsWith('.txt')).sort(); for (const f of files) { const raw = fs.readFileSync(path.join(dir, f), 'utf8'); const i = raw.indexOf('\n\n'); const url = raw.slice(5, i).trim(); let body = raw.slice(i + 2).trim(); const api = (url.match(/datacompass\.[A-Za-z0-9._]+/) || [''])[0]; const dt = (url.match(/recent\d+d/) || ['?'])[0]; let json = null, note = ''; try { json = JSON.parse(body); } catch { const m = body.match(/^[^(]*\((.*)\)[;\s]*$/s); if (m) { try { json = JSON.parse(m[1]); note = '(jsonp)'; } catch { note = '(unparsed)'; } } else note = '(unparsed)'; } console.log('='.repeat(78)); console.log(`${f} ${dt} ${api} ${note}`); if (!json) { console.log(' RAW HEAD: ' + body.slice(0, 300)); continue; } if (json.ret) console.log(' ret: ' + JSON.stringify(json.ret)); const data = json.data ?? json; const walk = (o, p, d) => { if (d > 3 || o === null || typeof o !== 'object') return; for (const k of Object.keys(o)) { const v = o[k]; const np = p ? p + '.' + k : k; if (Array.isArray(v)) { console.log(` ${np}[] len=${v.length}` + (v.length && typeof v[0] === 'object' ? ' keys=' + JSON.stringify(Object.keys(v[0])) : ' sample=' + JSON.stringify(v.slice(0, 8)))); if (v.length && typeof v[0] === 'object' && d < 2) walk(v[0], np + '[0]', d + 1); } else if (v && typeof v === 'object') { console.log(` ${np} {} keys=` + JSON.stringify(Object.keys(v))); walk(v, np, d + 1); } else { console.log(` ${np} = ${JSON.stringify(v)}`); } } }; walk(data, '', 0); }