应用或新功能发布后,用户反馈很快就会散落在短视频中。营销人员手动找到几条视频,把链接转发到聊天群里,分析师之后却难以判断哪些内容已经统计过,以及播放量如何变化。一个实用的解决方案是定期使用几组稳定的搜索词收集结果,保存原始响应,并根据已确认的字段生成报告。

本指南将针对一个具体场景配置这类收集流程:团队发布了一项新功能,希望每周追踪描述中提及产品名称、关键功能或典型用户问题的公开 TikTok 视频。这是对搜索结果样本的监测:API 会根据查询词和参数返回结果,并不保证列出所有有关此次发布的内容。
首先明确团队需要什么信号
仅凭播放量高低,很难判断下一步该做什么。团队更需要了解哪些问题反复出现、用户展示了哪些使用场景,以及哪些视频获得了显著的公开反响。因此,请先拟定几组搜索短语,并确定报告要包含哪些字段。
例如,对于一款内容发布计划工具,可以尝试搜索“产品名称”“内容排期工具”和“如何安排 TikTok 发布”。这些短语应反映人们描述同一主题时可能采用的不同说法。将搜索短语与监测开始日期和地区一起记录下来,以便之后在相同设置下比较各次导出结果。
最简表格可以包含收集时间、搜索短语、视频 ID、链接、描述、作者名称、作者 ID,以及可获取的播放量、点赞数和评论数。TikTok Scraper API 的文档说明,搜索结果中可能包含 aweme_id、desc、share_url、作者信息和部分统计数据。应逐个检查对象中的具体字段:某些指标可能缺失。
接入有文档说明的搜索接口
搜索视频时,使用基础地址 https://tiktok.evelode.com 上的 GET 路由 /searchVideo。文档列出了必需参数 keyword,以及可选参数 count、cursor、date_posted、sort_by、region 和 cache_timeout。日期筛选器的可用值包括 this-week,排序选项包括 relevance、most-liked 和 date-posted。参数用途和名称请参阅TikTok API 路由参考。
许可证密钥通过查询参数 license_key 传递。在正式脚本中,请从环境变量 JSONSCRAPER_TIKTOK_LICENSE_KEY 读取密钥,不要将其写入源代码或输出到日志中。以下示例适用于 Python 3.8+,并使用 requests 包:
import os
import requests
BASE_URL = "https://tiktok.evelode.com"
API_KEY = os.environ["JSONSCRAPER_TIKTOK_LICENSE_KEY"]
def search_videos(keyword, cursor=None):
params = {
"license_key": API_KEY,
"keyword": keyword,
"count": 20,
"date_posted": "this-week",
"sort_by": "date-posted",
"region": "US",
}
if cursor is not None:
params["cursor"] = cursor
response = requests.get(
f"{BASE_URL}/searchVideo",
params=params,
timeout=30,
)
response.raise_for_status()
payload = response.json()
if payload.get("status") != "ok":
raise RuntimeError("TikTok API 返回了非 ok 状态")
return payload["tiktok"]
result = search_videos("content planning app")
print("找到的对象:", len(result.get("aweme_list", [])))
该脚本会检查 HTTP 错误和响应的外层状态。HTTP 响应成功本身并不意味着搜索结果中一定有视频:如果样本为空,列表可能为空。首次运行时,建议将完整响应保存到安全存储中,以便把实际对象与规范化字段表进行核对。
解析两种搜索响应结构
搜索结果的结构有一个重要特点:视频可能直接位于 tiktok.aweme_list 中,也可能嵌套在 tiktok.search_item_list[].aweme_info 中。如果处理程序只读取第一个列表,就可能漏掉第二种结构中的结果。
加入一个小型规范化函数,同时支持这两种结构,并能跳过缺少嵌套视频对象的条目:
def extract_awemes(tiktok):
items = list(tiktok.get("aweme_list") or [])
for item in tiktok.get("search_item_list") or []:
aweme = item.get("aweme_info")
if aweme:
items.append(aweme)
return items
def normalize(aweme, keyword, collected_at):
author = aweme.get("author") or {}
stats = aweme.get("statistics") or {}
return {
"collected_at": collected_at,
"keyword": keyword,
"video_id": aweme.get("aweme_id"),
"posted_at": aweme.get("create_time"),
"description": aweme.get("desc"),
"share_url": aweme.get("share_url"),
"author_id": author.get("uid"),
"author_name": author.get("nickname"),
"views": stats.get("play_count"),
"likes": stats.get("digg_count"),
"comments": stats.get("comment_count"),
"shares": stats.get("share_count"),
}
缺失值应保留为 None。不要用零代替它:零表示测得的数值,而 None 则保留了该字段未返回这一事实。这一区别会影响平均值、比例以及团队据此得出的任何结论。
保存历史记录,而不只是当前快照
要查看变化趋势,请单独保存每次观测记录。视频 ID 适合用于视频去重,却不应作为删除历史记录的依据:同一条视频在下一次收集时再次出现,就会产生新的观测点。例如,可以用 video_id 和 collected_at 组成观测表的唯一键,并在记录中保存链接和描述,方便核查。
以下 SQLite 最简方案适用于原型开发:
import sqlite3
conn = sqlite3.connect("tiktok_observations.sqlite3")
conn.execute("""
CREATE TABLE IF NOT EXISTS observations (
video_id TEXT NOT NULL,
collected_at TEXT NOT NULL,
keyword TEXT NOT NULL,
posted_at INTEGER,
description TEXT,
share_url TEXT,
author_id TEXT,
author_name TEXT,
views INTEGER,
likes INTEGER,
comments INTEGER,
shares INTEGER,
PRIMARY KEY (video_id, collected_at, keyword)
)
""")
conn.commit()
实际使用时,请将收集时间统一为 UTC,单独保存原始 JSON,并添加一个模式版本字段。新的对象结构与以往不同的时候,原始响应有助于重新核查转换过程。如果某条视频通过多个查询词被发现,可将匹配到的查询词存入单独的关联表,或在生成报告时合并。
分页:只使用响应中返回的游标继续查询
cursor 参数用于继续搜索。其值应从上一条响应中获取,未经转换直接传回;当 has_more 不再表示还有后续内容,或达到指定上限时,就停止搜索。游标应视为不透明值:不要自行计算,也不要用页码计数器代替。
def collect_pages(keyword, max_pages=3):
cursor = None
collected = []
for _ in range(max_pages):
page = search_videos(keyword, cursor)
collected.extend(extract_awemes(page))
if not page.get("has_more"):
break
cursor = page.get("cursor")
if cursor is None:
break
return collected
限制页数有助于让定期任务的请求量保持可控。请在执行日志中记录页数和 has_more 的值,为报告中的样本规模提供背景。即使启用了分页,结果仍只代表 API 返回的内容和设定的收集上限,并不等于平台上所有相关视频的估算总量。
生成可重复的报告
可每周运行一次收集任务;如果团队需要更频繁地获取信号,也可以增加运行频率。每次运行都记录查询词列表、参数、时间、获取到的对象数量和唯一 ID 数量。另行统计本次首次发现的视频,以及此前已经出现过的视频。
报告中适合加入以下四类简单内容:
- 新视频:链接、描述、发布日期,以及发现该视频所用的搜索短语。
- 重复出现的主题:按人工设定的类别对描述进行分组,例如“设置错误”“功能需求”和“使用场景演示”。
- 公开互动数据:展示可获取的播放量、点赞数、评论数和分享数,并注明观测时间。
- 待核查信号:新的表达方式、常见问题,或值得员工进一步研究的视频。
如果没有核实响应中数值的含义和时效性,就不要把两个快照之间的差异称为“新增点赞”。更准确的说法是“最近一次收到的响应中的指标值”和“已保存快照之间的差异”。这样团队就能清楚地知道计算了什么,并在做出决策前打开原始视频核查。
让 AI 负责分类,而不是取代数据收集
完成规范化后,可以将视频描述交给模型,按预先定义的类别进行分类。只发送必要的文本字段,并要求模型返回结构化结果:类别、简短依据、置信度,以及作为标签依据的描述片段。将原始视频信息与标签一并保存,以便分析师复核有争议的案例。
工作流程可以保持简单:调度程序启动收集任务;Python 校验响应并保存 JSON;另一个任务规范化新记录;分类器只处理新的描述;报告从数据库生成,并发送到团队选定的渠道。TikTok Scraper API 本身提供搜索数据,分类和报告分发则属于集成逻辑,可用 Python、n8n 或 Make 实现。
为减少噪声,请在将数据交给模型前设定类别词表,并定期抽查人工标注的样本。遇到过短或含糊的描述时,使用“上下文不足”状态比强行分配类别更合适。AI 标签有助于对待审核内容排序,但有关用户问题的结论,应通过阅读原始视频并比较多次观测来确认。
错误、重试与密钥安全
网络请求可能超时、遇到临时故障,或收到无法解析为 JSON 的响应。请将处理过程分成几个阶段:发起请求、检查 HTTP 状态码、解析 JSON、检查外层状态、规范化和写入。遇到临时故障时,可设置有限次数的重试,并逐步延长等待时间;持续性错误应记录下来以便排查,不要将该次运行标记为成功。
请将密钥保存在运行环境的密钥管理器或环境变量中。由于 API 在查询字符串中接收 license_key,应避免记录完整 URL 和请求参数,以免密钥泄露。排查问题时,可记录路由、响应码、耗时、搜索短语和任务 ID,但要从日志中移除密钥。
请根据实际需求和平台使用条款设置运行频率及样本量。收集公开数据时,应限制在分析确实需要的范围内;团队内部规则也应说明描述、链接和作者 ID 的存储方式。API 响应和指标可能不完整,也可能在不同观测之间发生变化,因此报告应保留每一行数据的收集时间和来源。
最终成果:从手动转发链接到可核查的历史记录
配置完成后,团队将获得定期更新的已发现视频列表、供审计使用的原始响应、可获取的公开指标表,以及重复主题概览。这有助于团队更快发现有关新功能的问题、找到用户使用场景的示例,并挑选需要人工分析的视频。比较不同快照可以看出已发现视频的已保存指标值如何变化,而查询日志则能说明样本是如何生成的。
先从一个查询词和较小的页数上限开始,检查实际响应结构,再逐步增加其他搜索短语并设置运行计划。将原型部署到生产环境之前,请制定去重、存储和错误处理规则。最新的路由和参数可查阅官方 API 文档;功能说明和测试入口则位于TikTok Scraper API 页面。