12  Datensammlung: TikTok

12.1 Setup

12.1.1 Pakete laden

Zur Sammlung von TikTok-Daten nutzen wir das Paket traktok. Dieses bietet Funktionen für den Zugriff auf Daten über die TikTok Research API, für die man sich bewerben muss, sowie eine sogenannte “Hidden API” bzw. “Unofficial API” (über Web Scraping).

Wie immer müssen wir das Paket zunächst (einmalig) installieren und dann (in jeder Sitzung) laden.

install.packages("traktok")
library(traktok)

Zusätzlich nutzen wir auch in diesem Abschnitt Funktionen aus den tidyverse-Paketen. Sofern dies in der aktuellen R-Session noch nicht geschehen ist, müssen wir auch diese Pakete erst laden

library(tidyverse)

12.1.2 Authentifizierung

Wir nutzen hier die “Unofficial API”. Um diese nutzen zu können, müssen wir uns mit einem TikTok-Account im Browser einloggen und die Cookies für die Webseite speichern. Das geht am einfachsten mit den Browser-Plugins Get cookies.txt für Chrome bzw. cookies.txt für Firefox.

Sobald wir die Cookies für TikTok gespeichert haben, können wir sie mithilfe des R-Pakets cookiemonster speichern.

Auch dieses müssen wir natürlich erst einmal installieren und laden.

install.packages("cookiemonster")
library(cookiemonster)

Die Cookies können wir dann mit der Funktion add_cookies() speichern. Das Argument muss dabei der Pfad (siehe Kapitel 26) sein, unter dem die .txt-Datei mit den Cookies gespeichert ist.

add_cookies(path = "./data/tiktok_cookies.txt") # Dateipfad anpassen

Ob alles funktioniert hat, können wir dann mit der Funktion auth_check() aus dem Paket traktok überprüfen.

auth_check()
✔ Hidden API authenticated

Wichtiger Hinweis: Der Zugang über die “Hidden” bzw. “Unofficial API” ist nicht so stabil wie derjenige über die offizielle Research API. Es kann daher sein, dass Funktionen für die Hidden API nicht funktionieren, weil Anfragen geblockt werden. Es ist auch möglich, dass man bei der Verwendung dieser Funktionen im Browser Captchas lösen muss. Mehr dazu findet sich im Abschnitt zur Unofficial API in der Dokumentation von traktok.

12.2 Daten sammeln

Die Informationen zu den Accounts, von denen wir Daten sammeln wollen, stammen aus dem Datensatz Social-Media-Konten der Kandidierenden bei der Bundestagswahl 2025 (Breuer et al., 2026). Beispiele dafür, wie Sie Accounts aus diesem Datensatz auswählen können, finden Sie im Skript get_accounts.R.

Hinweis: Eine weitere Informationsquelle für TikTok-Accounts ist auch der Datensatz Social Media Accounts (TikTok, YouTube, X/Twitter) of the Candidates in the 2025 German Federal Election (Steup et al., 2025).

Wir wählen hier beispielhaft aus dem Datensatz von Breuer et al. (2026) Accounts von prominenten Politiker_innen von der CDU, der SPD, den Grünen, der Linken und der FDP.

tt_accounts <- c("serapguelermdb", "lars.klingbeil",
              "katharina.droege", "heidireichinnek",
              "christianduerr")

12.2.1 Profilinformationen

Profilinformationen zu einem Account können mit der Funktion tt_user_info_hidden() abgerufen werden

tt_user <- tt_user_info_hidden("serapguelermdb")

glimpse(tt_user)
Rows: 1
Columns: 46
$ id                               <chr> "6805862662515704837"
$ short_id                         <chr> ""
$ user_name                        <chr> "serapguelermdb"
$ nickname                         <chr> "Serap Güler"
$ avatar_larger                    <chr> "https://p19-common-sign.tiktokcdn-eu…
$ avatar_medium                    <chr> "https://p16-common-sign.tiktokcdn-eu…
$ avatar_thumb                     <chr> "https://p16-common-sign.tiktokcdn-eu…
$ signature                        <chr> "Staatsministerin im Auswärtigen Amt …
$ create_time                      <dttm> 2020-03-19 11:27:21
$ verified                         <lgl> FALSE
$ secUid                           <chr> "MS4wLjABAAAAVPaQKMby3pyhpm44VYipCEmV…
$ ftc                              <lgl> FALSE
$ relation                         <int> 0
$ open_favorite                    <lgl> FALSE
$ comment_setting                  <int> 0
$ commerce_user_info_commerce_user <lgl> FALSE
$ duet_setting                     <int> 0
$ stitch_setting                   <int> 0
$ private_account                  <lgl> FALSE
$ secret                           <lgl> FALSE
$ is_a_d_virtual                   <lgl> FALSE
$ room_id                          <chr> ""
$ unique_id_modify_time            <int> 0
$ tt_seller                        <lgl> FALSE
$ download_setting                 <int> 0
$ profile_tab_show_music_tab       <lgl> FALSE
$ profile_tab_show_question_tab    <lgl> FALSE
$ profile_tab_show_play_list_tab   <lgl> FALSE
$ following_visibility             <int> 1
$ recommend_reason                 <chr> ""
$ now_invitation_card_url          <chr> ""
$ nick_name_modify_time            <dttm> 2024-07-09 13:00:34
$ is_embed_banned                  <lgl> FALSE
$ can_exp_playlist                 <lgl> TRUE
$ profile_embed_permission         <int> 1
$ language                         <chr> "de"
$ suggest_account_bind             <lgl> FALSE
$ is_organization                  <int> 0
$ `_user_story_status`             <int> 0
$ follower_count                   <int> 1481
$ following_count                  <int> 48
$ heart                            <int> 5661
$ heart_count                      <int> 5661
$ video_count                      <int> 38
$ digg_count                       <int> 0
$ friend_count                     <int> 23

Um Profilinformationen zu mehreren Accounts gleichzeitig abzurufen, können wir die Funktion map_df() aus dem purrr-Paket nutzen. Diese führt eine Funktion für mehrere verschiedene Argumente (in unserem Fall Accounts) aus und verbindet die Ergebnisse zu einem Dataframe.

tt_users <- map_df(tt_accounts,
                 ~tt_user_info_hidden(username = .x)) # die Funktion wird für jeden Account aus dem Vektor "tt_accounts" ausgeführt, wobei ".x" den aktuellen Account aus der Liste repräsentiert 

glimpse(tt_users)
Rows: 5
Columns: 50
$ id                                 <chr> "6805862662515704837", "67573458688…
$ short_id                           <chr> "", "", "", "", ""
$ user_name                          <chr> "serapguelermdb", "lars.klingbeil",…
$ nickname                           <chr> "Serap Güler", "larsklingbeil", "Ka…
$ avatar_larger                      <chr> "https://p19-common-sign.tiktokcdn-…
$ avatar_medium                      <chr> "https://p16-common-sign.tiktokcdn-…
$ avatar_thumb                       <chr> "https://p16-common-sign.tiktokcdn-…
$ signature                          <chr> "Staatsministerin im Auswärtigen Am…
$ create_time                        <dttm> 2020-03-19 11:27:21, 2019-11-09 17:…
$ verified                           <lgl> FALSE, TRUE, FALSE, TRUE, FALSE
$ secUid                             <chr> "MS4wLjABAAAAVPaQKMby3pyhpm44VYipC…
$ ftc                                <lgl> FALSE, FALSE, FALSE, FALSE, FALSE
$ relation                           <int> 0, 0, 0, 0, 0
$ open_favorite                      <lgl> FALSE, FALSE, FALSE, FALSE, FALSE
$ comment_setting                    <int> 0, 0, 0, 0, 0
$ commerce_user_info_commerce_user   <lgl> FALSE, TRUE, FALSE, TRUE, FALSE
$ duet_setting                       <int> 0, 0, 0, 0, 0
$ stitch_setting                     <int> 0, 0, 0, 0, 0
$ private_account                    <lgl> FALSE, FALSE, FALSE, FALSE, FALSE
$ secret                             <lgl> FALSE, FALSE, FALSE, FALSE, FALSE
$ is_a_d_virtual                     <lgl> FALSE, FALSE, FALSE, FALSE, FALSE
$ room_id                            <chr> "", "", "", "", ""
$ unique_id_modify_time              <int> 0, 0, 0, 0, 0
$ tt_seller                          <lgl> FALSE, FALSE, FALSE, FALSE, FALSE
$ download_setting                   <int> 0, 0, 0, 0, 0
$ profile_tab_show_music_tab         <lgl> FALSE, FALSE, FALSE, FALSE, FALSE
$ profile_tab_show_question_tab      <lgl> FALSE, TRUE, FALSE, FALSE, FALSE
$ profile_tab_show_play_list_tab     <lgl> FALSE, FALSE, FALSE, TRUE, FALSE
$ following_visibility               <int> 1, 1, 1, 1, 1
$ recommend_reason                   <chr> "", "", "", "", ""
$ now_invitation_card_url            <chr> "", "", "", "", ""
$ nick_name_modify_time              <dttm> 2024-07-09 13:00:34, NA, 2024-11-17…
$ is_embed_banned                    <lgl> FALSE, FALSE, FALSE, FALSE, FALSE
$ can_exp_playlist                   <lgl> TRUE, TRUE, TRUE, TRUE, TRUE
$ profile_embed_permission           <int> 1, 1, 1, 1, 1
$ language                           <chr> "de", "de", "de", "de", "en"
$ suggest_account_bind               <lgl> FALSE, FALSE, FALSE, FALSE, FALSE
$ is_organization                    <int> 0, 0, 0, 1, 0
$ `_user_story_status`               <int> 0, 0, 0, 0, 0
$ follower_count                     <int> 1481, 35400, 10100, 689000, 7840
$ following_count                    <int> 48, 175, 156, 283, 97
$ heart                              <int> 5661, 360200, 129400, 22600000, 893…
$ heart_count                        <int> 5661, 360200, 129400, 22600000, 893…
$ video_count                        <int> 38, 167, 199, 432, 153
$ digg_count                         <int> 0, 0, 0, 0, 0
$ friend_count                       <int> 23, 84, 86, 182, 66
$ bio_link_link                      <chr> NA, "linktr.ee/larsklingbeil", "htt…
$ bio_link_risk                      <int> NA, 0, 0, 0, NA
$ commerce_user_info_category        <chr> NA, "Persönliches Konto", NA, "Öffe…
$ commerce_user_info_category_button <lgl> NA, FALSE, NA, FALSE, NA

Für eine Textanalyse können wir die Profilbeschreibungstexte der Accounts nutzen, die in der Variable signature zu finden sind.

12.2.2 Videos

Die Videos eines Accounts können mit der Funktion tt_user_videos_hidden() abgerufen werden. Leider funktioniert diese aktuell (Stand 26.05.2026) nicht verlässlich. Sie können ausprobieren, diese lokal auf Ihrem Rechner auszuführen. Es empfiehlt sich dabei, das Argument solve_captchas auf TRUE zu setzen, damit Sie ggf. erscheinende Captchas in Ihrem Browser lösen können.

Wenn Sie Freude am Lösen von CAPTCHAs haben/entwickeln (wollen), ist das Browser Game I’m Not a Robot zu empfehlen 🤖

tt_videos <- tt_uservideos_hidden("serapguelermdb",
                                  solve_captchas = TRUE)

glimpse(tt_videos)

12.2.3 Weitere Daten

Das Paket traktok bietet auch Funktionen, um Daten zu den Following und Followed Accounts zu sammeln. Dies geht mit den Funktionen tt_get_follower_hidden() bzw. tt_get_following_hidden()

Da wir uns im Kurs auf die Analyse von Textdaten konzentrieren und die Netzwerkanalyse ausklammern, werden wir diese Daten hier nicht weiter betrachten. Weitere Informationen zu diesen Funktionen finden Sie in der Dokumentation zum Paket atrrr.

Eine Einführung in die Netzwerkanalyse bietet u.a. Kapitel 13 im Online-Buch Computational Analysis of Communication.