

# 為內容分析研究準備 TikTok 字幕文字資料

可以。你核對公開的 TikTok 字幕之後，就可以收集這些字幕，做定量內容分析。定量內容分析是指：在你劃定的一組影片裡，數算一條清楚的內容規則。字幕軌是已經附在影片上的公開文字。在本文，字幕文字就是這個意思。它不是把每句說話再抄一份。核對是指你自己把字幕和影片比較。回傳的文字是字幕資料。它不是說話、畫面，或每一則 TikTok 帖文的完整紀錄。

一則公開的研究問題，問怎樣為一項研究收集 TikTok 字幕文字。它也問怎樣檢查準確度，以及怎樣在 R 裡分析文字。R 是用來處理表格和次數的程式。這條問題顯示有這個需要。它沒有證明這個方法有效。它也沒有顯示有多少研究需要它。見[關於 TikTok 字幕文字的公開問題](https://www.reddit.com/r/CompSocial/comments/1h1zijh/help_needed_scraping_tiktok_video_transcripts_for/)。

你用 Actor 收集資料行。Actor 是託管的資料收集程式。託管是指它以服務形式運行，不是你電腦上的一個檔案。這個 Actor 是 [TikTok Transcript Scraper](https://apify.com/chronometrica/tiktok-transcript-scraper)。Task 是已儲存的輸入預設。預設是一套已儲存的輸入選擇。目前的 Task 是 [TikTok Transcript Dataset for Content Analysis](https://apify.com/chronometrica/tiktok-transcript-scraper/examples/tiktok-transcript-content-analysis-dataset)。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`。擷取失敗和字幕失敗也可能出現。成功必須有非空白的文字。失敗狀態配上空值或空白字幕，並不是說話中的沉默。影片仍可能有說話。你只知道沒有可用的字幕回來。

只有成功的原生字幕結果，`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"]`。

然後[把一段短文字和聲音比較](/zh-Hant/articles/%E7%A0%94%E7%A9%B6%E5%89%8D%E6%A0%B8%E5%B0%8D-tiktok-%E5%AD%97%E5%B9%95%E7%94%A8%E5%AD%97/)。也看畫面上的影像。寫下漏掉的字、多出的字和錯誤的字。成功的一行不證明字詞準確。上面的 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`。真實狀態是未知時，不要把 `caption_validated` 寫成 no。失敗的一行沒有被核對。未完成的覆核也沒有被核對。

片段放在第二張表。用影片鍵、`startSeconds`、`endSeconds`、`text`，以及一項來源觀察。把片段陣列放在試算表的一個儲存格裡，是很差的匯出。CSV 是平面文字表，資料按行和欄排列。嵌套的片段清單不能安全地直接放進這種表格結構。先匯出 JSON。JSON 是一種文字格式，可以在一個項目裡保留清單。然後另行把片段清單攤平。攤平是指每個片段做成單獨的一行。在每個片段的那一行重複影片鍵。不要按逗號拆開文字。句子裡有逗號。原始字幕文字保持不變。每個編碼都放在新欄。

1. 寫一條小編碼規則，並在虛構例子上試用

從這一步起的例子都是虛構。它們不是 Actor 的輸出。不要把這些 ID 貼進真實輸入。它們的影片 URL 是未知的。

寫一條短規則，並給它一個版本。若是簡單的全字相符規則，要界定該字、字母大小寫，以及字詞邊界。字詞邊界避免一個短字在較長的字裡面相符。含糊用法由你自己覆核。關鍵字規則只找出該模式。它不證明說話的人想表達甚麼。只靠畫面傳達的訊息，可以和字幕文字不一致。諷刺也可以和文字不一致。這些情況需要人來編碼。

這裡的虛構編碼，是量度水的明確指示。規則版本 v1：已核對的字幕文字給出該指示時，標為編碼 1。整個字 "measure" 在任何字母大小寫都計算。字 "measurement" 是另一個字。要覆核它。不要只靠關鍵字規則標它。只有已核對、而且沒有該指示的字幕，才可以標編碼 0。否則編碼保持未知。

1. 先核對一小組試行資料，再匯入 R

大型研究之前，先為一小組試行資料編碼。兩個人可以分開編碼。或者你稍後再編一次，然後比較。儲存 `code`、`code_version`、`coder`、`decision_note` 和一個時間戳。時間戳記錄決定是何時作出的。原始文字放在自己的欄。

R 可以讀取平面 CSV。告訴 R，ID 欄是文字。不要讓 R 把 ID 猜成數字。下面的片段只用 base 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"]]))
```

八個步驟

你也可以在 base 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。在該占比旁邊，報告每條已選影片的結果。讀者必須看到失敗和未完成的行。把發現限制在你選中並觀察到的影片。不要把它說成所有創作者的結果。不要把它說成所有政治言論的結果。

缺失的字幕可以改變結論。本文停在這份清單。它不教[那些缺失的行可以令結果改變多少](/zh-Hant/articles/%E7%BC%BA%E5%A4%B1%E5%AD%97%E5%B9%95%E5%A6%82%E4%BD%95%E6%94%B9%E8%AE%8A%E7%A0%94%E7%A9%B6%E6%A8%A3%E6%9C%AC/)。

## 虛構的五條影片計數

同一個虛構例子在這裡繼續。V1 至 V5 是編造的研究標籤。`videoId` 的值是編造的文字標籤。它們不是真實的 TikTok ID。每一行的 `videoUrl` 都是未知。不要把這些標籤送給 Actor。真實的 `languageCode` 可以是地區值，例如 `eng-US`。這個虛構例子用 `en`，因為聲明的研究語言是英文。在表裡，unknown 是研究用的值。在 R 例子裡，`NA` 儲存同一個未知。不要把未知存成 0。

所聲明的編碼仍是量度水的明確指示。

V1 是英文。它成功。字幕已核對。文字是 "I measure the water before I pour it"。這段文字是量度水的明確指示。編碼是 1。

V2 是英文。它成功。字幕已核對。文字是 "I pour water into the tray"。它叫人倒水。它沒有叫人量度。編碼是 0。

V3 的狀態是 `no_public_captions`。文字是空白。`languageCode` 是未知。不要編造一個。`caption_validated` 是 unknown，不是 no。編碼是未知。空白文字不是編碼 0。它也不是沉默的證明。

V4 的狀態是 `language_unavailable`。文字是空白。`languageCode` 是未知。`caption_validated` 是 unknown。編碼是未知。這個失敗和 V3 的失敗不同。把兩個原因分開保留。

V5 是英文。它成功。有人把字幕和聲音比較。字幕漏了量度語句。核對未完成。`caption_validated` 是 unknown，不是 no。`study_eligible` 是 no。編碼保持未知。成功不等於可信的字幕。不要把這一行變成編碼 0。

只有 `study_eligible` 是 yes 時，影片才進入占比。這個決定和編碼分開。V1 和 V2 合資格，因為字幕成功、文字非空白，而且有人核對過。V3 和 V4 不合資格，因為收集失敗。V5 不合資格，因為核對未完成。V1、V2 和 V5 的 `isBillable` 會是 true，因為那些字幕結果成功。V3 和 V4 的 `isBillable` 會是 false。V5 可計費，但仍不合資格。可計費標記不決定研究中計算的影片數目。

影片表：

| selected_video_key | videoId | videoUrl | languageCode | caption_status | caption_validated | study_eligible | exclusion_reason |
| --- | --- | --- | --- | --- | --- | --- | --- |
| V1 | video-v1 | unknown | en | succeeded | yes | yes | none |
| V2 | video-v2 | unknown | en | succeeded | yes | yes | none |
| V3 | video-v3 | unknown | unknown | no_public_captions | unknown | no | 沒有公開字幕；空白文字未編碼 |
| V4 | video-v4 | unknown | unknown | language_unavailable | unknown | no | 所要求的語言缺失；空白文字未編碼 |
| V5 | video-v5 | unknown | en | succeeded | unknown | no | 聲音覆核未完成；漏了量度語句 |

編碼表：

| selected_video_key | code | code_version | coder | decision_note | timestamp |
| --- | --- | --- | --- | --- | --- |
| V1 | 1 | v1 | coder-a | 量度水的明確指示 | example-only |
| V2 | 0 | v1 | coder-a | 只有倒水的指示；沒有量度的指示 | example-only |
| V3 | unknown | v1 | coder-a | 字幕失敗；未觀察到編碼 | example-only |
| V4 | unknown | v1 | coder-a | 字幕失敗；未觀察到編碼 | example-only |
| V5 | unknown | v1 | coder-a | 字幕未核對；未觀察到編碼 | example-only |

片段表：

| selected_video_key | startSeconds | endSeconds | text | source_observation |
| --- | --- | --- | --- | --- |
| V1 | 0.5 | 2.5 | I measure the water before I pour it | 已核對的字幕證據，支持編碼 1 |
| V1 | unknown | unknown | unknown | 第二個量度片段；只作額外證據；這裡未設定時間 |
| V2 | unknown | unknown | I pour water into the tray | 已核對的字幕證據，支持編碼 0 |
| V5 | unknown | unknown | unknown | 字幕漏了一句已說出的量度語句；這裡未設定字詞 |

V3 和 V4 沒有片段行。它們的結果文字是空白。不要在 0 秒加一個片段。零會看起來像真實時間。缺失的時間保持未知。

第一個 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"
    }
  ]
}
```

虛構的五條影片計數

那個物件是給攤平步驟用的虛構例子。攤平之後，上面的片段表是編碼副本。影片表仍是計數副本。

## 下一步

收集完整清單之前，先核對一條已選的公開影片。檢查輸入、狀態行和編碼清單。使用 [TikTok Transcript Scraper](https://apify.com/chronometrica/tiktok-transcript-scraper) Actor，以及 [TikTok Transcript Dataset for Content Analysis](https://apify.com/chronometrica/tiktok-transcript-scraper/examples/tiktok-transcript-content-analysis-dataset) Task。用你自己已知的一個公開 URL，取代樣本影片。

## 來源與延伸閱讀

- [TikTok Transcript Scraper](https://apify.com/chronometrica/tiktok-transcript-scraper)
- [TikTok Transcript Dataset for Content Analysis](https://apify.com/chronometrica/tiktok-transcript-scraper/examples/tiktok-transcript-content-analysis-dataset)
- [關於 TikTok 影片字幕文字的公開問題](https://www.reddit.com/r/CompSocial/comments/1h1zijh/help_needed_scraping_tiktok_video_transcripts_for/)