// 快速烟测三平台 API 是否可用(江中采集前置验证) const https = require('https'); const fs = require('fs'); const os = require('os'); const path = require('path'); const TIKHUB = JSON.parse(fs.readFileSync( path.join(os.homedir(), '.openclaw', 'skills', 'xiaohongshu-search-notes', 'api-config.json'), 'utf8' )).endpoint.headers.Authorization.replace(/^Bearer\s+/, ''); function httpJson(opts, body = null, timeout = 30000) { return new Promise((resolve) => { const req = https.request({ ...opts, timeout }, (res) => { const chunks = []; res.on('data', (c) => chunks.push(c)); res.on('end', () => { const b = Buffer.concat(chunks).toString('utf-8'); let j = null; try { j = JSON.parse(b); } catch (e) { /* ignore */ } resolve({ status: res.statusCode, body: b, json: j }); }); }); req.on('error', (e) => resolve({ status: 0, err: e.message })); req.on('timeout', () => { req.destroy(); resolve({ status: 0, err: 'timeout' }); }); if (body) req.write(body); req.end(); }); } async function main() { console.log('=== 1) XHS search_notes (TikHub) ==='); const r1 = await httpJson({ hostname: 'server.fmode.cn', path: '/thapi/v1/xiaohongshu/app/search_notes?keyword=' + encodeURIComponent('肝纯片') + '&page=1', method: 'GET', headers: { Accept: 'application/json', Authorization: 'Bearer ' + TIKHUB }, }); const items = r1.json?.data?.data?.items || []; console.log(` status=${r1.status} items=${items.length}`); if (items.length) { const n = items[0].note; console.log(` sample: ${(n?.title || n?.desc || '').slice(0, 60)} · cmts=${n?.comments_count}`); global._sampleNoteId = n?.id; } console.log('\n=== 2) XHS get_note_comments ==='); if (global._sampleNoteId) { const r2 = await httpJson({ hostname: 'server.fmode.cn', path: '/thapi/v1/xiaohongshu/app/get_note_comments?note_id=' + global._sampleNoteId + '&cursor=', method: 'GET', headers: { Accept: 'application/json', Authorization: 'Bearer ' + TIKHUB }, }); const c = r2.json?.data?.data?.comments || []; console.log(` status=${r2.status} comments=${c.length} has_more=${r2.json?.data?.data?.has_more}`); if (c.length) console.log(` sample: ${(c[0].content || '').slice(0, 80)} | ♥ ${c[0].like_count}`); } console.log('\n=== 3) Douyin search (voc-social POST) ==='); // 读 voc-credentials.json 拿 vocToken const VOC = JSON.parse(fs.readFileSync( path.join(os.homedir(), '.openclaw', 'voc-credentials.json'), 'utf8' )).vocToken; const dyBody = JSON.stringify({ keyword: '肝纯片', cursor: 0, sort_type: '1', publish_time: '0', content_type: '1', filter_duration: '0', search_id: '', backtrace: '', }); const r3 = await httpJson({ hostname: 'server.fmode.cn', path: '/api/voc-social/douyin/search/fetch_general_search_v2', method: 'POST', headers: { Accept: 'application/json', 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(dyBody), Authorization: 'Bearer ' + VOC, }, }, dyBody); console.log(` status=${r3.status}`); if (r3.json) { const topKeys = Object.keys(r3.json).slice(0, 10).join(','); console.log(` json top keys: ${topKeys}`); const sample = (r3.body || '').slice(0, 500); console.log(` body sample: ${sample}`); } console.log('\n=== 4) Sorftime ProductQuery (milk thistle) ==='); const azBody = JSON.stringify({ path: '/api/ProductQuery', method: 'POST', body: { Page: 1, Query: '1', QueryType: '7', Pattern: 'milk thistle' }, query: { domain: 1 }, }); const r4 = await httpJson({ hostname: 'server-msq.fmode.cn', path: '/api/sorftime/forward', method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(azBody) }, }, azBody, 45000); console.log(` status=${r4.status}`); if (r4.json) { const data = r4.json?.Data ?? r4.json?.data ?? r4.json; const prods = data?.Products || []; console.log(` products=${prods.length} PageCount=${data?.PageCount}`); if (prods.length) { console.log(` sample: ${prods[0].Asin} · ${(prods[0].Brand || '').slice(0, 20)} · $${((prods[0].SalesPrice || 0) / 100).toFixed(2)}`); } } else { console.log(` body sample: ${(r4.body || '').slice(0, 400)}`); } } main().catch((e) => console.error(e));