#!/usr/bin/env node /** * 探测 TikHub 的抖音用户搜索正确 API 路径 */ const fs = require('fs'); const path = require('path'); const os = require('os'); const https = require('https'); const TIKHUB_TOKEN = JSON.parse( fs.readFileSync( path.join(os.homedir(), '.openclaw', 'skills', 'xiaohongshu-search-notes', 'api-config.json'), 'utf-8' ) ).endpoint.headers.Authorization.replace(/^Bearer\s+/, ''); const COOKIE = fs.readFileSync(path.resolve('data/douyin-cookie.txt'), 'utf-8').trim(); const keyword = '葵花药业'; const paths = [ // app v3 '/api/v1/douyin/app/v3/fetch_user_search_result', '/api/v1/douyin/app/v3/search_user', '/api/v1/douyin/app/v3/fetch_general_search_result', // web '/api/v1/douyin/web/fetch_user_search_result_v2', '/api/v1/douyin/web/fetch_user_search_result', '/api/v1/douyin/web/search_user', '/api/v1/douyin/web/fetch_general_search_result', '/api/v1/douyin/web/fetch_general_search_result_v2', // app v1/v2 '/api/v1/douyin/app/v1/fetch_user_search_result', '/api/v1/douyin/app/v2/fetch_user_search_result', ]; function get(apiPath, params) { const qs = Object.entries(params) .filter(([, v]) => v !== undefined && v !== null && v !== '') .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`) .join('&'); return new Promise((resolve) => { const opts = { hostname: 'api.tikhub.io', path: `${apiPath}?${qs}`, method: 'GET', headers: { Authorization: `Bearer ${TIKHUB_TOKEN}`, Accept: 'application/json' }, }; const req = https.request(opts, (res) => { const chunks = []; res.on('data', (c) => chunks.push(c)); res.on('end', () => { const body = Buffer.concat(chunks).toString('utf-8'); try { resolve({ status: res.statusCode, json: JSON.parse(body) }); } catch (e) { resolve({ status: res.statusCode, json: { _raw: body.slice(0, 200) } }); } }); }); req.on('error', (e) => resolve({ status: 0, json: { _error: e.message } })); req.setTimeout(20000, () => { req.destroy(); resolve({ status: 0, json: { _error: 'timeout' } }); }); req.end(); }); } const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); (async () => { const out = []; for (const p of paths) { await sleep(800); const r = await get(p, { keyword, cookie: COOKIE, offset: 0, count: 10 }); const status = r.status; const code = r.json?.code; const msg = r.json?.message_zh || r.json?.message || r.json?.detail?.message_zh || r.json?.detail?.message; const data = r.json?.data; const hasData = data != null && !Array.isArray(data) ? Object.keys(data).length : (Array.isArray(data) ? data.length : 0); const dataKeys = data && typeof data === 'object' && !Array.isArray(data) ? Object.keys(data).slice(0, 8).join(',') : ''; const line = { path: p, status, code, msg: (msg || '').slice(0, 80), hasData, dataKeys }; out.push(line); } fs.writeFileSync('data/dy-search-paths.json', JSON.stringify(out, null, 2), 'utf-8'); console.log(JSON.stringify(out, null, 2)); })();