Author: Produced by 43 COLLEGE 凯寓 (KAIYU) Version: v1.0
Retrieve data from 926+ social media interfaces via the TikHub API.
Initial configuration
If a command errors because config.json cannot be found, api_key is a placeholder, or a 401 is returned, read the SETUP.md in this directory and guide the user through configuration according to the process in it.
Cross-platform compatibility
| macOS / Linux | Windows | |
|---|---|---|
| Python command | python3 |
python |
| Skill path | ~/.claude/skills/social-media-scout/ |
%USERPROFILE%\.claude\skills\social-media-scout\ |
| JSON parameters | --args '{"key": "value"}' |
--args "{\"key\": \"value\"}" |
Invocation architecture (important, read this first)
This skill has two invocation paths; understanding this is the prerequisite for avoiding pitfalls:
| Mode | Address | Dependency | Applicable scenario |
|---|---|---|---|
| MCP mode | https://mcp.tikhub.io/tools/call |
Requires tikhub-mcp-proxy.exe to be running in the background |
When the proxy is already started |
| REST direct call | https://api.tikhub.io/api/v1/... |
No additional dependency, direct HTTP call | When the proxy is not running (common) |
call_tool() has implemented automatic fallback: it first tries MCP, and automatically switches to REST on 404/connection failure. You can also use rest_call() or CLI rest-call commands to go directly through REST.
Tool name → REST path mapping rules:
{platform}_{module}_{method} → /api/v1/{platform}/{module}/{method}
Example:
douyin_search_fetch_user_search→/api/v1/douyin/search/fetch_user_searchdouyin_web_handler_user_profile→/api/v1/douyin/web/handler_user_profile
HTTP method rules: Search types (tool names containing _search_) use POST + JSON body, and the rest use GET + query params. If guessed incorrectly, it will automatically retry with 405.
Resource locations
- Script directory:
scripts/(under the skill root directory, relative path) - API configuration:
scripts/config.json(contains API Key, MCP proxy path) - MCP proxy (Windows): configure according to the
config.jsoninmcp_proxy_exepath - MCP proxy (Mac): Not applicable, use REST direct call mode.
- TikHub documentation: https://docs.tikhub.io
- API Key management: https://user.tikhub.io
Use cases
- Query user profiles (Douyin/TikTok/Xiaohongshu, etc.)
- Search videos, notes, and posts related to keywords
- Parse video data via share links
- Get video comments, user followers/following lists
- View platform trending lists
- Download watermark-free videos
- Get WeChat Official Account article lists (requires ghid)
- Extract the content of specified WeChat Official Account articles
Invocation method
All commands must first cd to the skill root directory before execution. For Python commands, refer to the cross-platform compatibility table.
# macOS/Linux 示例(Windows 将 python3 替换为 python,单引号替换为转义双引号)
# 调用工具(MCP 优先,自动降级 REST)
python3 scripts/tikhub_client.py call <tool_name> --args '{"param": "value"}'
# 直接走 REST API(推荐,跳过 MCP 代理)
python3 scripts/tikhub_client.py rest-call <tool_name> --args '{"param": "value"}'
# 按平台列出工具
python3 scripts/tikhub_client.py list --platform douyin
# 按关键词搜索工具
python3 scripts/tikhub_client.py list --keyword search
Python inline invocation (recommended for complex tasks):
import os, sys
# 必须用绝对路径,确保从任何 cwd 都能加载
skill_dir = os.path.expanduser("~/.claude/skills/social-media-scout")
sys.path.insert(0, os.path.join(skill_dir, "scripts"))
from tikhub_client import call_tool, rest_call, parse_user_search_results, extract_video_url, download_file
Common tools quick reference
Douyin (douyin)
Search type (recommended douyin_search_*, more stable than douyin_web_fetch_*_search_* ):
| Scenario | Tool name | Key parameters |
|---|---|---|
| Comprehensive search | douyin_search_fetch_general_search_v1 |
keyword, cursor(0), sort_type("0") |
| Search users | douyin_search_fetch_user_search |
keyword, offset("0"), count("10") |
| Search videos | douyin_search_fetch_video_search_v1 |
keyword, cursor(0) |
User profile:
| Scenario | Tool name | Key parameters |
|---|---|---|
| User profile (sec_uid) | douyin_web_handler_user_profile |
sec_user_id |
| User profile (uid) | douyin_web_fetch_user_profile_by_uid |
uid |
| User profile (Douyin ID) | douyin_web_fetch_user_profile_by_short_id |
short_id |
Work retrieval (to get all works, use the App API; the Web API has a pagination depth limit of about 80 items):
| Scenario | Tool name | Key parameters |
|---|---|---|
| User works (App, recommended) | douyin_app_fetch_user_post_videos |
sec_user_id, max_cursor("0"), count("20") |
| User works (Web) | douyin_web_fetch_user_post_videos |
sec_user_id, max_cursor("0"), count("50") |
| Single video | douyin_web_fetch_one_video |
aweme_id |
| Share link parsing | douyin_web_fetch_one_video_by_share_url |
share_url |
| HD video link | douyin_app_fetch_video_high_quality_play_url |
aweme_id |
Interaction data:
| Scenario | Tool name | Key parameters |
|---|---|---|
| Video comments | douyin_web_fetch_video_comments |
aweme_id, cursor("0"), count("20") |
| Follower list | douyin_web_fetch_user_fans_list |
sec_user_id, max_time("0"), count("20") |
| Following list | douyin_web_fetch_user_following_list |
sec_user_id, max_time("0"), count("20") |
| Hot search ranking | douyin_web_fetch_hot_search_result |
None |
Xiaohongshu (xiaohongshu)
| Scenario | Tool name | Key parameters |
|---|---|---|
| User information | xiaohongshu_web_get_user_info |
user_id |
| Search notes | xiaohongshu_web_search_notes |
keyword, page(1), sort("general") |
| Search users | xiaohongshu_web_search_users |
keyword, page(1) |
| User note list (App, recommended) | xiaohongshu_app_get_user_notes |
user_id, cursor |
| User note list (Web) | xiaohongshu_web_get_user_notes_v2 |
user_id, cursor |
| Note comments | xiaohongshu_web_get_note_comments |
note_id, cursor |
Bilibili (bilibili)
Important: Bilibili APIs have poor stability; the web and app user profile/work list APIs frequently return 500. The following are reliable paths verified through actual testing.
Search category:
| Scenario | Tool name | Key parameters | Notes |
|---|---|---|---|
| Search users | bilibili_app_fetch_search_by_type |
keyword, search_type("bili_user"), page("1") |
Recommended, stable |
| Search videos | bilibili_app_fetch_search_by_type |
keyword, search_type("video"), page("1") |
Results mix multiple UP hosts and need to be filtered by author |
| Comprehensive search | bilibili_app_fetch_search_all |
keyword, page("1") |
Mixed types |
| Comprehensive search (Web) | bilibili_web_fetch_general_search |
keyword, search_type, page("1") |
Unstable, often 500 |
User profile (Reliable method for getting follower count):
| Scenario | Tool name | Key parameters | Notes |
|---|---|---|---|
| Follower/following count | bilibili_web_fetch_user_relation_stat |
vmid |
Most stable, but TikHub may also return 500 |
| User profile (Web) | bilibili_web_fetch_user_profile |
vmid |
Requires wbi signature, often 500 |
| User profile (App) | bilibili_app_fetch_user_info |
vmid |
Unstable |
| UP host total plays/likes | bilibili_web_fetch_user_up_stat |
vmid |
May return empty data |
If all TikHub APIs return 500, you can directly call Bilibili public APIs with Python as a fallback(using only built-in libraries, no additional dependencies required):
import urllib.request, json
mid = '目标UID'
headers = {'User-Agent': 'Mozilla/5.0 (compatible)', 'Referer': 'https://space.bilibili.com/'}
req = urllib.request.Request(f'https://api.bilibili.com/x/relation/stat?vmid={mid}', headers=headers)
with urllib.request.urlopen(req, timeout=10) as r:
data = json.loads(r.read())
# data['data']['follower'] = 粉丝数, data['data']['following'] = 关注数
# 此接口无需 wbi 签名,较稳定
Work retrieval (core pitfalls):
| Scenario | Tool name | Key parameters | Notes |
|---|---|---|---|
| ⭐ User dynamics (including videos) | bilibili_web_fetch_user_dynamic |
uid, offset("") |
The most reliable way to get a user's video list |
| User works (Web) | bilibili_web_fetch_user_post_videos |
mid, pn("1"), ps("10") |
Frequently 500 |
| User works (App) | bilibili_app_fetch_user_videos |
vmid, pn("1"), ps("10") |
Frequently 500 |
| Single video | bilibili_web_fetch_one_video |
bvid or aid |
- |
Interaction data:
| Scenario | Tool name | Key parameters |
|---|---|---|
| Video comments | bilibili_web_fetch_video_comments |
oid(video aid), type("1"), pn("1") |
| Video comments (App) | bilibili_app_fetch_video_comments |
oid, type("1"), pn("1") |
| Video danmaku | bilibili_web_fetch_video_danmaku |
oid(video cid) |
| Favorites | bilibili_web_fetch_collect_folders |
up_mid |
| BV to AID | bilibili_web_bv_to_aid |
bvid |
| Popular videos | bilibili_web_fetch_com_popular |
pn("1"), ps("20") |
| Trending searches | bilibili_web_fetch_hot_search |
None |
Bilibili recommendation workflow
Download Bilibili videos(TikHub is not applicable, yt-dlp must be used):
First check whether yt-dlp is installed:which yt-dlp(macOS/Linux) or where yt-dlp(Windows)。
If not installed, guide the user to install it:
# macOS(需要 Homebrew)
brew install yt-dlp
# Windows(需要 pip)
pip install yt-dlp
# Linux
pip3 install yt-dlp
Download command:
yt-dlp \
--output "/目标目录/文件名.%(ext)s" \
--format "bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best" \
--no-playlist \
"https://www.bilibili.com/video/BVxxx"
1080P 60fps requires a premium membership cookie (
--cookies-from-browser chrome), regular 1080P does not require login.
Standard process for querying UP主 information(to avoid pitfalls):
- Search user →
bilibili_app_fetch_search_by_type(search_type="bili_user")- In the returned results:
item[0].param= UID,item[0].author_new.fans= follower count (may be inaccurate)
- In the returned results:
- Get accurate follower count →
bilibili_web_fetch_user_relation_stat(vmid=UID)- If 500, fall back to directly calling with requests
api.bilibili.com/x/relation/stat
- If 500, fall back to directly calling with requests
- Get latest videos →
bilibili_web_fetch_user_dynamic(uid=UID, offset="")- Do not use
bilibili_web_fetch_user_post_videosorbilibili_app_fetch_user_videos, they often return 500 - The dynamic API returns about 12 items per page, use the returned
data.offsetto paginate - Video data is in
item.modules.module_dynamic.major.archivein
- Do not use
- Parse video data in dynamics:
items = resp['result']['data']['data']['items']
for item in items:
archive = item['modules']['module_dynamic']['major'].get('archive', {})
if archive: # 跳过纯文字/转发动态
title = archive['title']
bvid = archive['bvid']
stat = archive['stat'] # play, danmaku
duration = archive['duration_text']
pub_time = item['modules']['module_author']['pub_time']
TikTok
| Scenario | Tool name | Key parameters |
|---|---|---|
| User profile | tiktok_web_fetch_user_profile |
uniqueId |
| User works | tiktok_web_fetch_user_post |
secUid, cursor("0"), count("20") |
| Single video | tiktok_web_fetch_post_detail |
aweme_id |
| Search videos | tiktok_web_fetch_search_video |
keyword, cursor("0"), count("20") |
| Video comments | tiktok_web_fetch_post_comment |
aweme_id, cursor("0"), count("20") |
General
| Scenario | Tool name | Key parameters |
|---|---|---|
| Mixed parsing (any link) | hybrid_video_data |
url |
WeChat Official Account (wechat_mp)
Important: TikHub's WeChat Official Account API must be called directly via REST API, and cannot go through the MCP tool system (the /tools endpoint returns 404).
Call method (fixed template):
import urllib.request, json, urllib.parse, os
# 从 config.json 读取 API Key
skill_dir = os.path.expanduser("~/.claude/skills/social-media-scout")
with open(os.path.join(skill_dir, "scripts", "config.json")) as f:
api_key = json.load(f)["api_key"]
headers = {'Authorization': f'Bearer {api_key}', 'User-Agent': 'TikHub/1.0'}
def wechat_mp_get(path, params):
url = f'https://api.tikhub.io{path}?' + urllib.parse.urlencode(params)
req = urllib.request.Request(url, headers=headers)
with urllib.request.urlopen(req, timeout=30) as r:
return json.loads(r.read())
API list:
| Scenario | Path | Key parameters |
|---|---|---|
| Get Official Account article list | /api/v1/wechat_mp/web/fetch_mp_article_list |
ghid(required), offset(pagination) |
| Extract article content (JSON, cheap) | /api/v1/wechat_mp/web/fetch_mp_article_detail_json |
url(Only supports short links mp.weixin.qq.com/s/XXXX) |
| Extract article content (HTML, expensive) | /api/v1/wechat_mp/web/fetch_mp_article_detail_html |
url(supports both short and long links; the article list ContentUrl must use this API) |
| Get article comments | /api/v1/wechat_mp/web/fetch_mp_article_comment_list |
url, comment_id, buffer |
| Convert Sogou URL to WeChat URL | /api/v1/wechat_mp/web/fetch_mp_article_url |
sogou_url |
| Get related articles | /api/v1/wechat_mp/web/fetch_mp_related_articles |
url |
Article list return structure:
data = resp['data']
articles = data['list'] # 文章数组
next_offset = data['offset'] # 翻页游标,传给下次请求的 offset 参数
for a in articles:
title = a['Title']
url = a['ContentUrl'] # 文章长链,传给 fetch_mp_article_detail_html(JSON 接口不支持长链)
send_time = a['send_time'] # Unix 时间戳
cover = a['CoverImgUrl']
Article detail return structure:
data = resp['data']
title = data['title']
author = data['author']
ghid = data['publish_info']['user_id'] # 这就是公众号 ghid!
pub_time = data['publish_info'].get('type', '')
content_blocks = data['content']['raw_content'] # 结构化内容块列表
# 每个 block 有 type(p/h5/image/section) 和 text 字段
WeChat Official Account standard workflow
Known article URL → complete process(recommended entry):
- Extract ghid: call
fetch_mp_article_detail_json, get ghid fromdata.publish_info.user_idget ghid - Get article list: call
fetch_mp_article_list(ghid=result from previous step) - Extract specified article: call on the target article URL
fetch_mp_article_detail_json
Only the official account name → workaround path to get ghid(risky, Sogou may have anti-scraping):
- Open any article of that official account in the WeChat app, copy the link
- Pass the link to Claude, execute step 1
Note: TikHub has no "search by official account name" interface; ghid must be extracted from the URL of an article of that official account.
Workflow
- Identify the target platform
- Choose tools based on needs (search/profile/works/comments/download)
- For share links, prefer
*_by_share_urlorhybrid_video_data - When unsure of parameter names, use
list --keywordto look up - Call tools and format output
Pitfall records (important)
The following is supplementary experience not covered in the main text, with content duplicated from the preceding text removed.
General
- Parameter types: Most parameters need to be passed as strings (e.g.
"0"rather than0) - API billing: Each successful call is billed, avoid unnecessary repeated requests. The response contains
cache_urlwhich can be accessed repeatedly for free (valid for 24h) - General pagination deduplication strategy: When batch scraping on all platforms, use dict/set to deduplicate by ID, and set up a safety mechanism of "stop after N consecutive pages with no new data"
- Windows inline Python encoding: When handling Chinese/emoji, add at the beginning of the script
import sys; sys.stdout.reconfigure(encoding='utf-8'), or start withpython -X utf8.tikhub_client.pyalready has this handling built in
Douyin
- User search data structure is special:
douyin_search_fetch_user_searchThe returned user information is nested indynamic_patch.raw_data(JSON string), must useparse_user_search_results()to parse - Video download link fields are not uniform: Different interfaces return different field names (video_url/play_url/play_addr, etc.), use
extract_video_url()to handle uniformly
Xiaohongshu
- Web interface pagination has severe duplication:
xiaohongshu_web_get_user_notes_v2Pagination has about 60% duplication rate. To get all notes you must usexiaohongshu_app_get_user_notes(App interface), cursor takes thecursorfield of the last note on each page
Bilibili
- Search results mix multiple UP hosts:
bilibili_app_fetch_search_by_typeWhen searching videos, results include multiple UP hosts, must filter the target UP host byitem.av.authoranditem.av.midFilter target UP creator - UID has two formats:
item.paramis the new long UID (e.g. 3546620310326128),item.author_new.midis the old short mid (e.g. 1680175). When calling other interfaces, uniformly use the long UID (param field) - Dynamic data parsing path:
result.data.data.items[], video is inmodules.module_dynamic.major.archive(contains title/bvid/stat/duration_text), author is inmodules.module_author. Text-only/repost dynamics have no archive field and need to be skipped
WeChat Official Account
- Interface must go through REST API: The WeChat Official Account interface cannot be called through the MCP
/toolsendpoint (returns 404), must make direct HTTP requests - Cannot search by name: Must pass
ghid(formatgh_xxxxxxxx), obtained from the article details'data.publish_info.user_idGet - Sogou WeChat has severe anti-scraping: Getting ghid via Sogou automation is unreliable; the most reliable way is for the user to manually provide an article link
- Article URL format affects interface selection:
fetch_mp_article_detail_jsonOnly short links are accepted (mp.weixin.qq.com/s/XXXXX), long links must usefetch_mp_article_detail_html。wechat_mp_get_article_detail()Already handled automatically
Helper function description
tikhub_client.py The following helper functions are provided:
call_tool(name, args)- Call any TikHub tool (MCP preferred, automatically falls back to REST)rest_call(name, args)- Call the REST API directly (skipping the MCP proxy)list_tools(keyword, platform)- Search available toolsparse_user_search_results(response)- Parse the nested data of Douyin user searchextract_video_url(post_data, api_response)- Extract video links from various data structuresdownload_file(url, filepath)- Download files locallyextract_result_data(response)- Extract the data field from an API response