选定的视频卡片同时连到一份已核对的字幕台账和一张编码表,编码表旁边是一个缺失文本托盘。
在研究编码之前核对字幕文本。

一个公开的研究问题询问如何为一项研究采集 TikTok 字幕稿。它也询问如何检查准确性,以及如何在 R 中分析这些文本。R 是用来处理表格和计数的程序。这个问题表明存在一种需求。它并不证明这种方法有效。它也没有说明有多少研究需要它。见关于 TikTok 字幕稿的公开问题。

你用一个 Actor 采集数据行。Actor 是托管的数据采集程序。托管是指它作为服务运行,而不是作为你电脑上的一个文件。这个 Actor 是 TikTok Transcript Scraper。Task 是已保存的输入预设。预设是存储好的一组输入选择。当前 Task 是 TikTok Transcript Dataset for Content Analysis。Actor 采集来源行。编码和计数由你来做。一个公开 Task 只是起始输入。它并不表示分析会自行运行。

当前采集程序返回的内容

这些公开事实已在 2026-10-13 核对。当前版本是 0.1.36。每次运行在 `startUrls` 中接受 1 到 100 个已知的公开目标。目标可以是视频 URL、短链接或数字视频 ID。这个 Actor 不搜索个人主页、关键词或声音页面。你必须已经知道这些视频。

`preferredLanguages` 是公共字幕语言的有序列表。Actor 选取第一条匹配的公共字幕轨。空列表使用第一条公共字幕轨。它不翻译文本。它不为没有字幕的声音生成文本。它不采集评论。它不分配内容编码。

已保存的 Task 输入是:

json
{"startUrls": ["https://www.tiktok.com/@hankgreen1/video/7047596209028074758"], "preferredLanguages": []}
当前采集程序返回的内容

把该示例换成你自己已知的公开视频。做单视频试点时,在 `startUrls` 中放入一个 URL。如果英语是你的研究语言,把 `preferredLanguages` 设为 `["en"]`。如果研究使用另一种语言,写下该语言规则并使用它的代码。不要把 `["en"]` 复制到另一种语言的研究中。空列表可能返回某条其他公共字幕轨。

一个数据集行对应每一个提交的输入。失败的输入仍然有一行。保留该行。它是这次尝试的证据。这些字段名称是精确的:`inputIndex`、`inputUrl`、`videoId`、`videoUrl`、`authorHandle`、`durationSeconds`、`languageCode`、`text`、`segments`、`status`、`statusReason`、`isBillable` 和 `scrapedAt`。每个片段有 `startSeconds`、`endSeconds` 和 `text`。TikTok 时间使用这两个键。按返回的原样使用 `startSeconds` 和 `endSeconds`。把每个 `videoId` 当作文本保留,不要当作数字。如果程序把长 ID 存成数字,这个 ID 可能会改变。

`status` 可以是 `succeeded`、`no_public_captions`、`language_unavailable`、`duplicate_input`、`not_tiktok`、`invalid_input`、`unsupported_url`、`video_unavailable`、`not_public` 或 `blocked_or_challenged`。还可能出现提取失败和字幕失败。成功要求文本不是空的。失败状态下的 null 或空字幕稿并不是口播里的静音。视频里仍可能有语音。你只知道没有返回可用字幕。

`isBillable` 仅在原生字幕稿结果成功时为 true。字段名中的 b 是小写。其他行作为证据留在数据中。`isBillable` 不描述整次运行。一次运行可以同时有 true 行和 false 行。不要把整次运行称为免费。

运行账使用这些精确名称:`inputsReceived`、`resultRows`、`billableTranscriptRows`、`nonBillableResultRows`、`duplicateVideosSkipped` 和 `statusCounts`。这份运行账用来核对这次运行。它并不表明你的视频代表所有创作者。

在 2026-10-13 用已保存的示例做了一次单视频检查。该行成功。视频 ID 是所请求的 ID,`7047596209028074758`。语言代码是 `eng-US`。像 `eng-US` 这样的代码是地区字幕标签。它表示带有美国地区标记的英语。它不是翻译。文本不是空的。该行有 12 个片段。片段时间具有 `startSeconds` 和 `endSeconds` 这种形状。这里不重复该视频的字幕词。这次检查证明那一个来源上存在公开字幕路径。它不证明词语完全正确。它不证明每条视频都会成功。它不证明你的内容编码有效。你自己的试点仍然是必需的。

八项操作

  1. 界定问题、编码和样本

写下一个研究问题。写下一条你可以计数的内容编码。内容编码是你标为存在或不存在的特征。按一条你能够陈述的规则选择已知视频 URL。在采集之前写明时间范围、语言和创作者范围。

抽样台账是你选定的每一条视频的清单。在查看字幕之前填好这份台账。不要只因为存在字幕就选择视频。如果你只保留有字幕的视频,样本就已经变了。没有字幕的视频会消失,而不会显示为缺失。

  1. 声明计数单位

选择你要计数的单位。单位可以是一条视频、一个字幕片段,或你定义的一段文字。在这些步骤里,计数单位是视频。片段是带时间的一段字幕文本。片段是该视频的证据。它们不是额外的视频。

三个片段即使编码相同,仍然算一条视频。在运行之前写下这条规则。保留输入 URL、返回的 `videoId` 和你自己的 `selected_video_key`。研究键是你的。即使 URL 形式改变,它也保持不变。

  1. 测试一条选定视频

在任何批量运行之前,先运行一条选定视频。这是试点。试点是对整条路径的小型测试。检查 `status`、`videoId`、`languageCode` 和 `text`。成功时文本必须非空。如果研究语言是英语,在这次试点中把 `preferredLanguages` 设为 `["en"]`。

然后把一段短文本和音频对照。同时看屏幕上的画面。记下漏掉的词、多出的词和错误的词。成功的一行并不能证明词语准确。上面的 12 个片段检查只说明公开路径可以返回字幕。那不是你的核对。

  1. 运行有界列表并核对

一次运行只发送你已知的 URL,最多 100 个。更长的选定列表需要另一次运行。把每一个提交的输入对应到一行结果。使用 `inputIndex`、`inputUrl` 和 `videoId`。把这些行与运行账核对。

检查 `inputsReceived`、`resultRows`、`billableTranscriptRows`、`nonBillableResultRows`、`duplicateVideosSkipped` 和 `statusCounts`。把重复项留在笔记中,并将该视频只计数一次。把缺失字幕留在台账中,但放在成功集合之外。来源访问失败也同样处理。这些状态包括 `video_unavailable`、`not_public`、`blocked_or_challenged`、`unsupported_url`、`not_tiktok` 和 `invalid_input`。

切勿把失败的空文本编码为“编码不存在”。空文本表示你没有观察到该编码。它并不表示该编码不存在。

  1. 制作视频表和片段表

为每条选定视频做一行。使用这些列:`selected_video_key`、`videoId`、`videoUrl`、`languageCode`、`caption_status`、`caption_validated`、`study_eligible` 和 `exclusion_reason`。`study_eligible` 记录该视频是否可以进入计数。它不是内容编码。`caption_validated` 记录你是否对照视频核对了字幕。

无法核对字幕时使用 `unknown`。真实状态是 unknown 时,不要把 `caption_validated` 写成 no。失败的一行没有经过核对。未完成的复查也没有经过核对。

片段放在第二张表。使用视频键、`startSeconds`、`endSeconds`、`text` 和一项来源观察。把片段数组放进一个电子表格单元格是糟糕的导出。CSV 是扁平的文本表。嵌套列表不能安全地放进这种扁平形状。先导出 JSON。JSON 是可以在一个项目内保留列表的文本格式。然后有意地展平。展平是指为每个片段做成表格中的一行。在每个片段行上重复视频键。不要按逗号拆分文本。句子里含有逗号。保持原始字幕文本不变。把每个编码放进新列。

  1. 写一条简单的编码规则,并用虚构例子测试这条规则

从这一步起的例子都是虚构的。它们不是 Actor 的输出。不要把这些 ID 粘贴到真实输入中。它们的视频 URL 是未知的。

写一条简短规则,并给它一个版本。对于简单的整词精确规则,要定义词、字母大小写和词边界。词边界避免一个短词匹配到更长词的内部。含义含糊的用法要自己复查。关键词规则只找出该模式。它不证明说话人的意思。只靠画面表达的要点可以和词语不一致。讽刺也可以和词语不一致。这些情况需要人来编码。

这里的虚构编码是明确要求量水的指令。规则版本 v1 在已核对的字幕文本给出该指令时标记编码 1。整词“measure”在任何字母大小写下都计数。词“measurement”是另一个词。要复查它。不要只靠关键词规则标记它。只有已核对、且没有该指令的字幕才可以标编码 0。否则编码保持 unknown。

  1. 检查一个试点集合,然后在 R 中导入

在大型研究之前,先给一个小试点集合编码。可以由两个人各自独立编码。也可以由你稍后再次编码并比较。保存 `code`、`code_version`、`coder`、`decision_note` 和时间戳。时间戳记录做出决定的时间。原始文本放在单独的列中。

R 可以读取扁平的 CSV。告诉 R:ID 列是文本。不要让 R 把 ID 猜成数字。下面的代码片段只用 R 自带功能。它使用虚构行。它不添加程序包。它不是经过检验的研究标准。这里 `denom` 是分母。分母是你用来做除法的合格视频数量。`NA` 表示不可用。本例用 `NA` 表示未知编码。

r
videos <- data.frame(
  videoId = c("video-v1", "video-v2", "video-v3", "video-v4", "video-v5"),
  study_eligible = c("yes", "yes", "no", "no", "no"),
  code = c(1, 0, NA, NA, NA),
  stringsAsFactors = FALSE
)
stopifnot(is.character(videos[["videoId"]]))
eligible <- videos[["study_eligible"]] == "yes"
stopifnot(!any(is.na(videos[["code"]][eligible])))
code_count <- sum(videos[["code"]][eligible])
denom <- sum(eligible)
share <- code_count / denom
八项操作

`code_count` 是 1。`denom` 是 2。`share` 是 0.5。这些 `NA` 是未知编码。它们不是零。`stopifnot` 那一行会在合格视频带有未知编码时停止脚本。

导出真实 CSV 时,保留同样的文本检查:

r
videos_from_csv <- read.csv(
  "video_table.csv",
  stringsAsFactors = FALSE,
  colClasses = c(videoId = "character")
)
stopifnot(is.character(videos_from_csv[["videoId"]]))
八项操作

你也可以在 R 自带功能中测试这条虚构的词规则:

r
raw_text <- "I measure the water before I pour it"
hit <- grepl("\\bmeasure\\b", raw_text, ignore.case = TRUE)
ambiguous <- grepl("\\bmeasure\\b", "measurement", ignore.case = TRUE)
八项操作

`hit` 是 TRUE。`ambiguous` 是 FALSE。第二个结果说明:更长的词需要人工复查规则,而不能静默匹配。

  1. 连同完整结果台账报告计数

计算该编码所占比例时,只用合格视频作分母。合格是指 `succeeded`、文本非空,并且 `caption_validated` 为 yes。在该比例旁边报告每一条选定视频的结果。读者必须能看到失败行和未完成行。把发现限制在你选定并观察到的视频。不要把它说成所有创作者的结果。不要把它说成全部政治言论的结果。

缺失字幕可能改变结论。本文停在台账。它不讲授这些缺失行能使结果改变多少。

五条虚构视频的计数

同样的虚构在这里继续。V1 到 V5 是编造的研究标签。`videoId` 的值是编造的文本标签。它们不是真实的 TikTok ID。每一行的 `videoUrl` 都是未知的。不要把这些标签发送给 Actor。真实的 `languageCode` 可以是地区值,例如 `eng-US`。这份虚构使用 `en`,因为声明的研究语言是英语。在表中,unknown 是研究用的值。在 R 例子中,`NA` 存储同一个未知。不要把 unknown 存成 0。

声明的编码仍然是明确要求量水的指令。

V1 是英语。它成功了。字幕已核对。文本是“I measure the water before I pour it”。这段文本是明确要求量水的指令。编码是 1。

V2 是英语。它成功了。字幕已核对。文本是“I pour water into the tray”。它让人去倒。它没有让人去量。编码是 0。

V3 的状态是 `no_public_captions`。文本是空的。`languageCode` 是 unknown。不要编造一个。`caption_validated` 是 unknown,不是 no。编码是 unknown。空文本不是编码 0。它也不是静音的证据。

V4 的状态是 `language_unavailable`。文本是空的。`languageCode` 是 unknown。`caption_validated` 是 unknown。编码是 unknown。这次失败和 V3 的失败不是同一种。把两个原因分开保留。

V5 是英语。它成功了。有人把字幕和音频做了对照。字幕漏掉了测量用语。核对没有完成。`caption_validated` 是 unknown,不是 no。`study_eligible` 是 no。编码保持 unknown。成功不等于可信的字幕。不要把这一行改成编码 0。

只有当 `study_eligible` 是 yes 时,视频才进入比例。这个决定和编码是分开的。V1 和 V2 合格,因为字幕成功、文本非空,并且有人核对过。V3 和 V4 不合格,因为采集失败。V5 不合格,因为核对没有完成。V1、V2 和 V5 的 `isBillable` 会是 true,因为那些字幕稿结果成功了。V3 和 V4 的 `isBillable` 会是 false。V5 可计费,但仍然不合格。计费标志不决定研究计数。

视频表:

五条虚构视频的计数
selected_video_keyvideoIdvideoUrllanguageCodecaption_statuscaption_validatedstudy_eligibleexclusion_reason
V1video-v1unknownensucceededyesyesnone
V2video-v2unknownensucceededyesyesnone
V3video-v3unknownunknownno_public_captionsunknownno没有公开字幕;空文本未编码
V4video-v4unknownunknownlanguage_unavailableunknownno请求的语言缺失;空文本未编码
V5video-v5unknownensucceededunknownno音频核对未完成;漏掉了测量用语

编码表:

五条虚构视频的计数
selected_video_keycodecode_versioncoderdecision_notetimestamp
V11v1coder-a明确要求量水的指令example-only
V20v1coder-a只有倾倒指令;没有量取指令example-only
V3unknownv1coder-a字幕失败;未观察到编码example-only
V4unknownv1coder-a字幕失败;未观察到编码example-only
V5unknownv1coder-a字幕未核对;未观察到编码example-only

片段表:

五条虚构视频的计数
selected_video_keystartSecondsendSecondstextsource_observation
V10.52.5I measure the water before I pour it已核对的字幕,作为编码 1 的证据
V1unknownunknownunknown第二条测量片段;只是额外证据;此处未设定时间
V2unknownunknownI pour water into the tray已核对的字幕,作为编码 0 的证据
V5unknownunknownunknown字幕漏掉了一句口播的测量用语;此处未写入那些词

V3 和 V4 没有片段行。它们的结果文本是空的。不要添加一条 0 秒的片段。零会看起来像真实时间。缺失的时间仍是 unknown。

第一段 V1 片段在 2.5 秒结束,在 0.5 秒开始。2.5 减 0.5 是 2.0 秒。这个长度使用 `endSeconds` 和 `startSeconds`。第二段 V1 片段也支持测量编码。它不会变成第二条视频。V1 仍然是一条已编码的视频。计数单位是视频。

已核对且合格的视频:2。编码为 1 的视频:1。1 / 2 = 0.5,即 50%。选定台账仍有 5 条视频。1 / 5 = 0.2,即 20%。不要报告 20%。V3、V4 和 V5 没有被核实为编码 0。未知不是零。

这五条选定视频的结果计数:2 条已核对且合格,2 条失败,1 条核对未完成。两次失败的状态不同。一个是 `no_public_captions`。另一个是 `language_unavailable`。

假设你把这五个输入提交了一次。假设没有重复。下面预期的运行账是根据这份虚构做的算术。它不是真实回执。`inputsReceived` 会是 5。`resultRows` 会是 5。`billableTranscriptRows` 会是 3。`nonBillableResultRows` 会是 2。`duplicateVideosSkipped` 会是 0。`statusCounts` 会显示 `succeeded` 3、`no_public_captions` 1 和 `language_unavailable` 1。你的真实运行必须对照你实际收到的运行账来检查。

这个例子说明额外片段不会增加视频。它也说明合格分母。它没有展示一组真实视频。它没有展示字幕准确率。它没有展示超出这些编造行的效应。

已知 V1 片段的扁平 JSON 形状是:

json
{
  "videoId": "video-v1",
  "segments": [
    {
      "startSeconds": 0.5,
      "endSeconds": 2.5,
      "text": "I measure the water before I pour it"
    }
  ]
}
五条虚构视频的计数

该对象是为展平步骤准备的虚构对象。展平之后,上面的片段表是编码副本。视频表仍然是计数副本。

来源和延伸阅读

作者 Chronometrica · 更新日期

返回顶部 ↑