| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133 |
- #!/usr/bin/env node
- /** 深入探测两条路径的完整 response 结构,锁定抖音搜索可用接口 */
- 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 VOC_TOKEN = JSON.parse(fs.readFileSync(
- path.join(os.homedir(), '.openclaw', 'voc-credentials.json'), 'utf-8'
- )).vocToken;
- function req(hostname, pathUrl, method, body, token) {
- return new Promise((resolve) => {
- const headers = { Authorization: `Bearer ${token}`, Accept: 'application/json' };
- const opts = { hostname, path: pathUrl, method, headers };
- if (body) {
- headers['Content-Type'] = 'application/json';
- headers['Content-Length'] = Buffer.byteLength(body);
- }
- const r = https.request(opts, (res) => {
- const chunks = [];
- res.on('data', (c) => chunks.push(c));
- res.on('end', () => resolve({ status: res.statusCode, body: Buffer.concat(chunks).toString('utf-8') }));
- });
- r.on('error', (e) => resolve({ status: 0, body: e.message }));
- r.setTimeout(30000, () => { r.destroy(); resolve({ status: 0, body: 'timeout' }); });
- if (body) r.write(body);
- r.end();
- });
- }
- function summarize(obj, depth = 0, prefix = '') {
- if (depth > 4) return '...';
- if (obj == null) return String(obj);
- if (Array.isArray(obj)) {
- if (obj.length === 0) return '[]';
- return `Array(${obj.length}) [0]=${summarize(obj[0], depth + 1, prefix + ' ')}`;
- }
- if (typeof obj === 'object') {
- const keys = Object.keys(obj);
- if (keys.length === 0) return '{}';
- const parts = keys.slice(0, 6).map((k) => {
- const v = obj[k];
- if (typeof v === 'string') return `${k}:"${v.slice(0, 30)}"`;
- if (typeof v === 'number') return `${k}:${v}`;
- if (typeof v === 'boolean') return `${k}:${v}`;
- if (Array.isArray(v)) return `${k}:Arr(${v.length})`;
- if (typeof v === 'object' && v != null) return `${k}:{${Object.keys(v).slice(0, 3).join(',')}}`;
- return `${k}:${typeof v}`;
- });
- return `{${parts.join(', ')}${keys.length > 6 ? ', ...' : ''}}`;
- }
- return typeof obj === 'string' ? `"${obj.slice(0, 40)}"` : String(obj);
- }
- (async () => {
- const kw = '江中猴菇';
- console.log(`🔎 keyword = "${kw}"\n`);
- // —— 1) TikHub direct on fmode /thapi/v1/ proxy ——
- console.log('━━━ 1) TikHub proxy /thapi/v1 (GET, TikHub token) ━━━');
- const r1 = await req('server.fmode.cn',
- `/thapi/v1/douyin/app/v3/fetch_general_search_result?keyword=${encodeURIComponent(kw)}&offset=0&count=20&sort_type=0&publish_time=0`,
- 'GET', null, TIKHUB_TOKEN);
- console.log(`status = ${r1.status}`);
- if (r1.status === 200) {
- try {
- const j = JSON.parse(r1.body);
- console.log('outer:', summarize(j));
- const inner = j.data ?? j;
- console.log('data:', summarize(inner));
- if (inner?.data) console.log('data.data:', summarize(inner.data));
- if (inner?.data?.[0]) {
- const v = inner.data[0];
- console.log('sample[0] keys:', Object.keys(v).slice(0, 20).join(', '));
- if (v.aweme_info) {
- console.log('aweme_info:', summarize(v.aweme_info));
- }
- }
- } catch (e) { console.log('PARSE ERR', e.message, r1.body.slice(0, 300)); }
- } else { console.log(r1.body.slice(0, 400)); }
- console.log();
- // —— 2) voc-social gateway (POST, voc token) ——
- console.log('━━━ 2) voc-social gateway (POST, vocToken) ━━━');
- const searchBody = JSON.stringify({
- keyword: kw, cursor: 0, sort_type: '0', publish_time: '0',
- filter_duration: '0', content_type: '0', search_id: '', backtrace: '',
- });
- const r2 = await req('server.fmode.cn',
- '/api/voc-social/douyin/search/fetch_general_search_v2',
- 'POST', searchBody, VOC_TOKEN);
- console.log(`status = ${r2.status}`);
- if (r2.status === 200) {
- try {
- const j = JSON.parse(r2.body);
- console.log('outer:', summarize(j));
- if (j?.data) console.log('data:', summarize(j.data));
- if (j?.data?.data) console.log('data.data:', summarize(j.data.data));
- } catch (e) { console.log('PARSE ERR', e.message, r2.body.slice(0, 300)); }
- } else { console.log(r2.body.slice(0, 400)); }
- console.log();
- // —— 3) Try official api.tikhub.io directly ——
- console.log('━━━ 3) api.tikhub.io direct (GET, TikHub token) ━━━');
- const r3 = await req('api.tikhub.io',
- `/api/v1/douyin/app/v3/fetch_general_search_result?keyword=${encodeURIComponent(kw)}&offset=0&count=20&sort_type=0&publish_time=0`,
- 'GET', null, TIKHUB_TOKEN);
- console.log(`status = ${r3.status}`);
- if (r3.status === 200) {
- try {
- const j = JSON.parse(r3.body);
- console.log('outer:', summarize(j));
- const inner = j.data ?? j;
- if (inner?.data) console.log('data.data:', summarize(inner.data));
- if (Array.isArray(inner?.data) && inner.data[0]) {
- const v = inner.data[0];
- console.log('first aweme keys:', Object.keys(v).slice(0, 15).join(', '));
- if (v.aweme_info || v.aweme_mix_info) {
- const info = v.aweme_info || v.aweme_mix_info;
- console.log('aweme_info keys:', Object.keys(info).slice(0, 20).join(', '));
- console.log('aweme_id:', info.aweme_id, '| author:', info.author?.nickname, '| stats:', summarize(info.statistics || {}));
- }
- }
- } catch (e) { console.log('PARSE ERR', e.message, r3.body.slice(0, 300)); }
- } else { console.log(r3.body.slice(0, 400)); }
- })();
|