From 4dde026257b76c9775522bbeba3b7de5a29f3aca Mon Sep 17 00:00:00 2001
From: JBGruber When you want to continue this search, whether because of rate limit
or because you decided you want more results, you can do so by providing
44UBXR(KXa+KmRc~)F>YSOyV2(
diff --git a/articles/research-api.html b/articles/research-api.html
index 5dfc2d5..bec6770 100644
--- a/articles/research-api.html
+++ b/articles/research-api.html
@@ -448,7 +448,11 @@ Dealing with rate
search_id
and cursor
to
-tt_search_api
:tt_search_api
. If your search was cut short by the rate
+limit or another issue, you can retrieve the results already received
+with search_df <- last_query()
. search_df
+will in both cases contain the relevant search_id
and
+cursor
in the attributes:
<- query() |>
search_df2 query_and(field_name = "region_code",
operation = "IN",
diff --git a/favicon-16x16.png b/favicon-16x16.png
index 83c03b6f365e97a351504198eee8193b081bbd0b..4cac126fb0842c234f628cf5b737a4a3ff07fde0 100644
GIT binary patch
delta 95
zcmcc2ahYSoG$syVUJI^|ws9{u&tqa_bhQjIG`2D|vobW$HZZU ℹ Making initial request ✔ Making initial request [734ms] #> ℹ Parsing data ✔ Parsing data [21ms] #> ── search id: NA ─────────────────────────────────────────── #> # A tibble: 0 × 11 #> # ℹ 11 variables: video_id , author_name , #> # view_count , comment_count , #> # region_code , create_time , #> # effect_ids , music_id , #> # video_description , hashtag_names , #> # voice_to_text tt_query_videos(\"#rstats\", max_pages = 2L, start_date = as.Date(\"2023-11-01\"), end_date = as.Date(\"2023-11-29\")) #> ℹ Making initial request ✔ Making initial request [1.1s] #> ℹ Parsing data ✔ Parsing data [30ms] #> ── search id: 7336340473469998126 ────────────────────────── #> # A tibble: 19 × 11 #> video_id author_name view_count comment_count region_code #> #> 1 7306893… statistics… 21 4 DE #> 2 7306307… learningca… 129 12 US #> 3 7305014… picanumeros 57 1 ES #> 4 7302970… smooth.lea… 5568 7 AU #> 5 7302470… statistics… 45 1 DE #> 6 7300977… statistics… 1403 0 DE #> 7 7300931… rigochando 1541 5 MX #> 8 7300922… elartedeld… 87 0 ES #> 9 7299987… statistics… 81 1 DE #> 10 7299657… rigochando 795 5 MX #> 11 7299342… rigochando 375 1 MX #> 12 7298966… rigochando 1183 2 MX #> 13 7296911… biofreelan… 2537 5 MX #> 14 7296911… biofreelan… 1363 0 MX #> 15 7296911… biofreelan… 680 1 MX #> 16 7296688… mrpecners 60 2 US #> 17 7296518… l_a_kelly 10 5 GB #> 18 7296498… mrpecners 19 0 US #> 19 7296288… casaresfel… 266 0 AR #> # ℹ 6 more variables: create_time , #> # effect_ids , music_id , #> # video_description , hashtag_names , #> # voice_to_text query() |> # start by using query() query_or(field_name = \"hashtag_name\", # add an OR condition on the hashtag field operation = \"IN\", # the value should IN the list of hashtags field_values = \"rstats\") |> # the hashtag field does not accept the #-symbol query_or(field_name = \"keyword\", # add another OR condition operation = \"IN\", field_values = \"#rstats\") #> S3 #> └─or: #> ├─ #> │ ├─field_name: \"hashtag_name\" #> │ ├─operation: \"IN\" #> │ └─field_values: #> │ └─\"rstats\" #> └─ #> ├─field_name: \"keyword\" #> ├─operation: \"IN\" #> └─field_values: #> └─\"#rstats\" search_df <- query() |> query_and(field_name = \"region_code\", operation = \"IN\", field_values = c(\"JP\", \"US\")) |> query_or(field_name = \"hashtag_name\", operation = \"EQ\", # rstats is the only hashtag field_values = \"rstats\") |> query_or(field_name = \"keyword\", operation = \"IN\", # rstats is one of the keywords field_values = \"rstats\") |> query_not(operation = \"EQ\", field_name = \"video_length\", field_values = \"SHORT\") |> tt_search_api(start_date = as.Date(\"2023-11-01\"), end_date = as.Date(\"2023-11-29\")) #> ℹ Making initial request ✔ Making initial request [734ms] #> ℹ Parsing data ✔ Parsing data [17ms] search_df #> ── search id: 7336340473470030894 ────────────────────────── #> # A tibble: 2 × 11 #> video_id author_name view_count comment_count region_code #> #> 1 72966888… mrpecners 60 2 US #> 2 72964986… mrpecners 19 0 US #> # ℹ 6 more variables: create_time , #> # effect_ids , music_id , #> # video_description , hashtag_names , #> # voice_to_text "},{"path":"https://jbgruber.github.io/traktok/articles/research-api.html","id":"get-basic-user-information","dir":"Articles","previous_headings":"Usage","what":"Get Basic User Information","title":"Research API","text":"really much getting basic user info, can :","code":"tt_user_info_api(username = c(\"tiktok\", \"https://www.tiktok.com/@statisticsglobe\")) #> # A tibble: 2 × 8 #> display_name follower_count following_count is_verified #> #> 1 TikTok 78785286 30 TRUE #> 2 Statistics Glo… 289 1 FALSE #> # ℹ 4 more variables: likes_count , video_count , #> # avatar_url , bio_description "},{"path":"https://jbgruber.github.io/traktok/articles/research-api.html","id":"obtain-all-comments-of-a-video","dir":"Articles","previous_headings":"Usage","what":"Obtain all Comments of a Video","title":"Research API","text":", much talk comes comments API. need supply video ID, either already: got search: let function extract URL video: essentially . Note, find functionality Research API lacking, nothing keeps using unofficial API functions.","code":"tt_comments_api(video_id = \"7302470379501604128\") #> ℹ Making initial request ✔ Making initial request [7.2s] #> ℹ Parsing data ✔ Parsing data [18ms] #> ── search id: ───────────────────────────────────────────── #> # A tibble: 1 × 7 #> text video_id create_time id like_count #> #> 1 and why would we do… 7302470… 1700243424 7302… 0 #> # ℹ 2 more variables: parent_comment_id , #> # reply_count tt_comments_api(video_id = search_df$video_id[1]) #> ✔ Making initial request [55.7s] #> ℹ Parsing data ✔ Parsing data [18ms] #> ── search id: ───────────────────────────────────────────── #> # A tibble: 2 × 7 #> like_count parent_comment_id reply_count text video_id #> #> 1 1 7296688856609475882 1 So co… 7296688… #> 2 0 7296690681388204831 0 Thank… 7296688… #> # ℹ 2 more variables: create_time , id tt_comments_api(video_id = \"https://www.tiktok.com/@nicksinghtech/video/7195762648716152107?q=%23rstats\") #> ℹ Making initial request ✔ Making initial request [2m 16.7s] #> ℹ Parsing data ✔ Parsing data [19ms] #> ── search id: ───────────────────────────────────────────── #> # A tibble: 96 × 7 #> create_time id like_count parent_comment_id #> #> 1 1675394834 719576596990925… 314 7195762648716152… #> 2 1675457114 719603344301613… 232 7195762648716152… #> 3 1675458796 719604066348022… 177 7195762648716152… #> 4 1675395061 719576692726561… 166 7195765969909252… #> 5 1675624739 719675339339355… 71 7195762648716152… #> 6 1675465779 719607064381200… 71 7195762648716152… #> 7 1675494738 719619490971140… 27 7195762648716152… #> 8 1675691471 719703995331384… 17 7196040663480222… #> 9 1675656122 719688817955866… 16 7195762648716152… #> 10 1675440749 719596313215706… 16 7195762648716152… #> # ℹ 86 more rows #> # ℹ 3 more variables: reply_count , text , #> # video_id "},{"path":"https://jbgruber.github.io/traktok/articles/research-api.html","id":"dealing-with-rate-limits-and-continuing-old-searches","dir":"Articles","previous_headings":"","what":"Dealing with rate limits and continuing old searches","title":"Research API","text":"moment writing vignette, TikTok rate limits Research API follows: Currently, daily limit set 1000 requests per day, allowing obtain 100,000 records per day across APIs. (Video Comments API can return 100 records per request). daily quota gets reset 12 UTC. [Source] Depending like , might enough . case, can actually save search pick back reset. facilitate , search result objects contain two extra pieces information attributes: want continue search, whether rate limit decided want results, can providing search_id cursor tt_search_api: Note cursor equal many videos got , API also counts videos “deleted/marked private users etc.” [See max_count Query Videos].","code":"search_df <- query() |> query_and(field_name = \"region_code\", operation = \"IN\", field_values = c(\"JP\", \"US\")) |> tt_search_api(start_date = as.Date(\"2023-11-01\"), end_date = as.Date(\"2023-11-29\"), max_pages = 1) #> ℹ Making initial request ✔ Making initial request [1.9s] #> ℹ Parsing data ✔ Parsing data [20ms] attr(search_df, \"search_id\") #> [1] \"7336340473470063662\" attr(search_df, \"cursor\") #> [1] 100 search_df2 <- query() |> query_and(field_name = \"region_code\", operation = \"IN\", field_values = c(\"JP\", \"US\")) |> tt_search_api(start_date = as.Date(\"2023-11-01\"), end_date = as.Date(\"2023-11-29\"), # this part is new start_cursor = attr(search_df, \"cursor\"), search_id = attr(search_df, \"search_id\"), #### max_pages = 1) #> ℹ Making initial request ✔ Making initial request [5.1s] #> ℹ Parsing data ✔ Parsing data [21ms] attr(search_df2, \"search_id\") #> [1] \"7336340473470063662\" attr(search_df2, \"cursor\") #> [1] 200"},{"path":"https://jbgruber.github.io/traktok/articles/unofficial-api.html","id":"authentication","dir":"Articles","previous_headings":"","what":"Authentication","title":"Unofficial API","text":"easiest way get cookies needed authentication export necessary cookies browser using browser extension (logging TikTok.com least ). can recommend “Get cookies.txt” Chromium based browsers “cookies.txt” Firefox (note almost browsers used today based one ). Save cookies.txt file, look something like : matter download cookies just ones specific TikTok, use cookiemonster package deal . read cookies specific encrypted file, simply use: ’s ! traktok access cookies whenever necessary.","code":"# Netscape HTTP Cookie File # https://curl.haxx.se/rfc/cookie_spec.html # This is a generated file! Do not edit. .tiktok.com TRUE / TRUE 1728810805 cookie-consent {%22ga%22:true%2C%22af%... .tiktok.com TRUE / TRUE 1700471788 passport_csrf_token e07d3487c11ce5258a3... .tiktok.com TRUE / FALSE 1700471788 passport_csrf_token_default e07d3487c11... #HttpOnly_.tiktok.com TRUE / TRUE 1700493610 multi_sids 71573310862246389... #HttpOnly_.tiktok.com TRUE / TRUE 1700493610 cmpl_token AgQQAPORF-RO0rNtH... ... cookiemonster::add_cookies(\"tiktok.com_cookies.txt\")"},{"path":[]},{"path":"https://jbgruber.github.io/traktok/articles/unofficial-api.html","id":"search-videos","dir":"Articles","previous_headings":"Usage","what":"Search videos","title":"Unofficial API","text":"search videos, can use either tt_search tt_search_hidden, , long token Research API. get first two pages search results (one page 12 videos), can use command: already gives pretty much information want videos found.","code":"rstats_df <- tt_search_hidden(\"#rstats\", max_pages = 2) #> ℹ Getting page 1 ⏲ waiting 0.5 seconds ℹ Getting page 1 ✔ Got page 1. Found 12 videos. [1.9s] #> ℹ Getting page 2 ✔ Got page 2. Found 12 videos. [690ms] rstats_df #> # A tibble: 24 × 20 #> video_id video_timestamp video_url video_length video_title #> #> 1 71151144… 2022-06-30 19:17:53 https://… 135 \"R for Beg… #> 2 72522261… 2023-07-05 07:01:45 https://… 36 \"Wow!!! TH… #> 3 72420686… 2023-06-07 22:05:16 https://… 34 \"R GRAPHIC… #> 4 72134135… 2023-03-22 16:49:12 https://… 6 \"R and me … #> 5 72576898… 2023-07-20 00:23:40 https://… 56 \"Pie chart… #> 6 72999870… 2023-11-10 23:58:21 https://… 51 \"Quick R Q… #> 7 72783048… 2023-09-13 13:40:21 https://… 36 \"Quick R Q… #> 8 73029706… 2023-11-19 00:56:09 https://… 163 \"What is c… #> 9 71670108… 2022-11-17 15:42:56 https://… 58 \"Here’s an… #> 10 72933174… 2023-10-24 00:36:48 https://… 9 \"#CapCut #… #> # ℹ 14 more rows #> # ℹ 15 more variables: video_diggcount , #> # video_sharecount , video_commentcount , #> # video_playcount , video_is_ad , author_name , #> # author_nickname , author_followercount , #> # author_followingcount , author_heartcount , #> # author_videocount , author_diggcount , …"},{"path":"https://jbgruber.github.io/traktok/articles/unofficial-api.html","id":"get-metadata-and-download-videos","dir":"Articles","previous_headings":"Usage","what":"Get metadata and download videos","title":"Unofficial API","text":"However, can obtain information, importantly video file, using tt_videos: Per default, function waits one ten seconds (chosen random) making two calls, make obvious data scraped TikTok. can speed process (risk), changing sleep_pool argument, controls minimum maximum number seconds wait: scraping lot URLs, function might fail eventually, due poor connection TikTok blocking requests. therefore usually makes sense save progress cache directory: Note video files downloaded dir directory (working directory default), independently cache directory. information feel missing data.frame tt_videos returns, can look raw, unparsed json data using: Parsing result list using fromJSON, results rather complex nested list. can look see data interested ","code":"rstats_df2 <- tt_videos(rstats_df$video_url[1:2], save_video = TRUE) #> ℹ Getting video 7115114419314560298 ⏲ waiting 0.2 seconds ℹ Getting video 7115114419314560298 ✔ Got video 7115114419314560298 (1/2). File size: 2.5 Mb. [2.5s] #> ℹ Getting video 7252226153828584731 ✔ Got video 7252226153828584731 (2/2). File size: 1.7 Mb. [999ms] rstats_df2 #> # A tibble: 2 × 19 #> video_id video_url video_timestamp video_length video_title #> #> 1 711511441… https://… 2022-06-30 19:17:53 135 R for Begi… #> 2 725222615… https://… 2023-07-05 07:01:45 36 Wow!!! THI… #> # ℹ 14 more variables: video_locationcreated , #> # video_diggcount , video_sharecount , #> # video_commentcount , video_playcount , #> # author_username , author_nickname , #> # author_bio , download_url , html_status , #> # music , challenges , is_classified , #> # video_fn rstats_df3 <- tt_videos(rstats_df$video_url[3:4], save_video = TRUE, sleep_pool = 0.1) #> ℹ Getting video 7242068680484408581 ⏲ waiting 0.1 seconds ℹ Getting video 7242068680484408581 ✔ Got video 7242068680484408581 (1/2). File size: 1.8 Mb. [2.6s] #> ℹ Getting video 7213413598998056234 ✔ Got video 7213413598998056234 (2/2). File size: 598.1 Kb. [1.7s] rstats_df3 #> # A tibble: 2 × 19 #> video_id video_url video_timestamp video_length video_title #> #> 1 724206868… https://… 2023-06-07 22:05:16 34 \"R GRAPHIC… #> 2 721341359… https://… 2023-03-22 16:49:12 6 \"R and me … #> # ℹ 14 more variables: video_locationcreated , #> # video_diggcount , video_sharecount , #> # video_commentcount , video_playcount , #> # author_username , author_nickname , #> # author_bio , download_url , html_status , #> # music , challenges , is_classified , #> # video_fn rstats_df3 <- tt_videos(rstats_df$video_url[5:6], cache_dir = \"rstats\") #> ℹ Getting video 7257689890245201153 ⏲ waiting 1.7 seconds ℹ Getting video 7257689890245201153 ✔ Got video 7257689890245201153 (1/2). File size: 1.7 Mb. [2.6s] #> ℹ Getting video 7299987059417042209 ✔ Got video 7299987059417042209 (2/2). File size: 1.2 Mb. [1.8s] list.files(\"rstats\") #> [1] \"7257689890245201153.json\" \"7299987059417042209.json\" rstats_list1 <- tt_request_hidden(rstats_df$video_url[1]) |> jsonlite::fromJSON()"},{"path":"https://jbgruber.github.io/traktok/articles/unofficial-api.html","id":"get-followers-and-who-a-user-is-following","dir":"Articles","previous_headings":"Usage","what":"Get followers and who a user is following","title":"Unofficial API","text":"Getting followers user following (moment?) little tricky use, since TikTok blocks requests users profile page anti-scraping measures. circumvent , can open users page browser right-click show source code:1 can search copy authorSecId value: authorSecId can look maximum 5,000 followers per account: Likewise, can also check account follows:","code":"tt_get_follower(secuid = \"MS4wLjABAAAAwiH32UMb5RenqEN7duyfLIeGQgSIx9WtgtOILt55q6ueUXgz4gHqZC5HFx4nabPi\", verbose = FALSE) #> #> # A tibble: 1,116 × 27 #> avatarLarger avatarMedium avatarThumb commentSetting #> #> 1 https://p16-sign-sg.tik… https://p16… https://p1… 0 #> 2 https://p16-sign-va.tik… https://p16… https://p1… 0 #> 3 https://p16-sign-va.tik… https://p16… https://p1… 0 #> 4 https://p16-sign-va.tik… https://p16… https://p1… 0 #> 5 https://p16-sign-va.tik… https://p16… https://p1… 0 #> 6 https://p16-sign-va.tik… https://p16… https://p1… 0 #> 7 https://p16-sign-va.tik… https://p16… https://p1… 0 #> 8 https://p16-sign-va.tik… https://p16… https://p1… 0 #> 9 https://p16-sign-va.tik… https://p16… https://p1… 0 #> 10 https://p16-sign-va.tik… https://p16… https://p1… 0 #> # ℹ 1,106 more rows #> # ℹ 23 more variables: downloadSetting , duetSetting , #> # ftc , id , isADVirtual , nickname , #> # openFavorite , privateAccount , relation , #> # secUid , secret , signature , #> # stitchSetting , ttSeller , uniqueId , #> # verified , diggCount , followerCount , … tt_get_following(secuid = \"MS4wLjABAAAAwiH32UMb5RenqEN7duyfLIeGQgSIx9WtgtOILt55q6ueUXgz4gHqZC5HFx4nabPi\", verbose = FALSE) #> #> # A tibble: 489 × 28 #> avatarLarger avatarMedium avatarThumb commentSetting #> #> 1 https://p16-sign-va.tik… https://p16… https://p1… 0 #> 2 https://p16-sign-va.tik… https://p16… https://p1… 0 #> 3 https://p16-sign-va.tik… https://p16… https://p1… 0 #> 4 https://p16-sign-va.tik… https://p16… https://p1… 0 #> 5 https://p16-sign-va.tik… https://p16… https://p1… 0 #> 6 https://p16-sign-va.tik… https://p16… https://p1… 0 #> 7 https://p16-sign-va.tik… https://p16… https://p1… 0 #> 8 https://p16-sign-va.tik… https://p16… https://p1… 0 #> 9 https://p16-sign-va.tik… https://p16… https://p1… 0 #> 10 https://p16-sign-va.tik… https://p16… https://p1… 0 #> # ℹ 479 more rows #> # ℹ 24 more variables: downloadSetting , duetSetting , #> # ftc , id , isADVirtual , nickname , #> # openFavorite , privateAccount , relation , #> # secUid , secret , signature , #> # stitchSetting , ttSeller , uniqueId , #> # verified , diggCount , followerCount , … list.files(pattern = \".mp4\") |> unlink() unlink(\"rstats\", recursive = TRUE)"},{"path":"https://jbgruber.github.io/traktok/authors.html","id":null,"dir":"","previous_headings":"","what":"Authors","title":"Authors and Citation","text":"Johannes B. Gruber. Author, maintainer.","code":""},{"path":"https://jbgruber.github.io/traktok/authors.html","id":"citation","dir":"","previous_headings":"","what":"Citation","title":"Authors and Citation","text":"Gruber, Johannes B. (2023). traktok. R package scrape data TikTok. R package version 0.0.4.9000. https://github.com/JBGruber/traktok.","code":"@Manual{, title = {traktok. Getting TikTok data through the official and unofficial APIs}, author = {Johannes B. Gruber}, year = {2023}, url = {https://github.com/JBGruber/traktok}, note = {R package version 0.0.4.9000}, }"},{"path":[]},{"path":"https://jbgruber.github.io/traktok/index.html","id":"feature-overview","dir":"","previous_headings":"","what":"Feature overview","title":"Collecting TikTok Data","text":"goal traktok provide easy access TikTok data. package one started R port Deen Freelon’s Pyktok Python module (though complete rewrite without Python dependencies). now covers functions secret hidden API TikTok using show/search/play videos Website official Research API. Since Research API misses important features (since everyone access ) can often make sense still use hidden API mocks requests browser. However, important disclaimer hidden API applies: program may stop working suddenly TikTok changes stores data (see Freelon, 2018). However, last times, fixed rather quickly (e.g., #12).","code":""},{"path":"https://jbgruber.github.io/traktok/index.html","id":"installation","dir":"","previous_headings":"","what":"Installation","title":"Collecting TikTok Data","text":"can install development version traktok GitHub :","code":"# install.packages(\"remotes\") remotes::install_github(\"JBGruber/traktok\")"},{"path":"https://jbgruber.github.io/traktok/reference/auth_hidden.html","id":null,"dir":"Reference","previous_headings":"","what":"Authenticate for the hidden/unofficial API — auth_hidden","title":"Authenticate for the hidden/unofficial API — auth_hidden","text":"Guides authentication hidden/unofficial API#'","code":""},{"path":"https://jbgruber.github.io/traktok/reference/auth_hidden.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Authenticate for the hidden/unofficial API — auth_hidden","text":"","code":"auth_hidden(cookiefile)"},{"path":"https://jbgruber.github.io/traktok/reference/auth_hidden.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Authenticate for the hidden/unofficial API — auth_hidden","text":"cookiefile optional path cookiefile. See vignette(\"unofficial-api\", package = \"traktok\") information authentication.","code":""},{"path":"https://jbgruber.github.io/traktok/reference/auth_hidden.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Authenticate for the hidden/unofficial API — auth_hidden","text":"nothing. Called set authentication","code":""},{"path":"https://jbgruber.github.io/traktok/reference/auth_hidden.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Authenticate for the hidden/unofficial API — auth_hidden","text":"","code":"if (FALSE) { # to run through the steps of authentication auth_hidden() # or point to a cookie file directly auth_hidden(\"www.tiktok.com_cookies.txt\") }"},{"path":"https://jbgruber.github.io/traktok/reference/auth_research.html","id":null,"dir":"Reference","previous_headings":"","what":"Authenticate for the official research API — auth_research","title":"Authenticate for the official research API — auth_research","text":"Authenticate official research API","code":""},{"path":"https://jbgruber.github.io/traktok/reference/auth_research.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Authenticate for the official research API — auth_research","text":"","code":"auth_research(client_key, client_secret)"},{"path":"https://jbgruber.github.io/traktok/reference/auth_research.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Authenticate for the official research API — auth_research","text":"client_key Client key authentication client_secret Client secret authentication","code":""},{"path":"https://jbgruber.github.io/traktok/reference/auth_research.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Authenticate for the official research API — auth_research","text":"authentication token","code":""},{"path":"https://jbgruber.github.io/traktok/reference/auth_research.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Authenticate for the official research API — auth_research","text":"need apply access API get key secret TikTok. See https://developers.tiktok.com/products/research-api/ information.","code":""},{"path":"https://jbgruber.github.io/traktok/reference/auth_research.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Authenticate for the official research API — auth_research","text":"","code":"if (FALSE) { auth_research(client_key, client_secret) }"},{"path":"https://jbgruber.github.io/traktok/reference/last_query.html","id":null,"dir":"Reference","previous_headings":"","what":"Retrieve most recent query — last_query","title":"Retrieve most recent query — last_query","text":"tt_search_api tt_comments_api fail already getting several pages, can use function get videos retrieved far memory. work session crashed. case, look tempdir() RDS file last resort.","code":""},{"path":"https://jbgruber.github.io/traktok/reference/last_query.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Retrieve most recent query — last_query","text":"","code":"last_query() last_comments()"},{"path":"https://jbgruber.github.io/traktok/reference/last_query.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Retrieve most recent query — last_query","text":"list unparsed videos","code":""},{"path":"https://jbgruber.github.io/traktok/reference/print.traktok_query.html","id":null,"dir":"Reference","previous_headings":"","what":"Print a traktok query — print.traktok_query","title":"Print a traktok query — print.traktok_query","text":"Print traktok query tree","code":""},{"path":"https://jbgruber.github.io/traktok/reference/print.traktok_query.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Print a traktok query — print.traktok_query","text":"","code":"# S3 method for traktok_query print(x, ...)"},{"path":"https://jbgruber.github.io/traktok/reference/print.traktok_query.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Print a traktok query — print.traktok_query","text":"x object class traktok_query ... Additional arguments passed lobstr::tree","code":""},{"path":"https://jbgruber.github.io/traktok/reference/print.traktok_query.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Print a traktok query — print.traktok_query","text":"","code":"query() |> query_and(field_name = \"hashtag_name\", operation = \"EQ\", field_values = \"rstats\") |> print() #> S3 #> └─and: #> └─ #> ├─field_name: \"hashtag_name\" #> ├─operation: \"EQ\" #> └─field_values: #> └─\"rstats\""},{"path":"https://jbgruber.github.io/traktok/reference/print.tt_results.html","id":null,"dir":"Reference","previous_headings":"","what":"Print search result — print.tt_results","title":"Print search result — print.tt_results","text":"Print traktok search results","code":""},{"path":"https://jbgruber.github.io/traktok/reference/print.tt_results.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Print search result — print.tt_results","text":"","code":"# S3 method for tt_results print(x, ...)"},{"path":"https://jbgruber.github.io/traktok/reference/print.tt_results.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Print search result — print.tt_results","text":"x object class tt_results ... used.","code":""},{"path":"https://jbgruber.github.io/traktok/reference/query.html","id":null,"dir":"Reference","previous_headings":"","what":"Create a traktok query — query","title":"Create a traktok query — query","text":"Create traktok query given parameters.","code":""},{"path":"https://jbgruber.github.io/traktok/reference/query.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Create a traktok query — query","text":"","code":"query(and = NULL, or = NULL, not = NULL) query_and(q, field_name, operation, field_values) query_or(q, field_name, operation, field_values) query_not(q, field_name, operation, field_values)"},{"path":"https://jbgruber.github.io/traktok/reference/query.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Create a traktok query — query","text":", , list //conditions. Must contain one multiple lists field_name, operation, field_values (see example). q traktok query created query. field_name field name query . One : \"create_date\", \"username\", \"region_code\", \"video_id\", \"hashtag_name\", \"keyword\", \"music_id\", \"effect_id\", \"video_length\". operation One : \"EQ\", \"\", \"GT\", \"GTE\", \"LT\", \"LTE\". field_values vector values search .","code":""},{"path":"https://jbgruber.github.io/traktok/reference/query.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Create a traktok query — query","text":"traktok query.","code":""},{"path":"https://jbgruber.github.io/traktok/reference/query.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Create a traktok query — query","text":"TikTok's query consists rather complicated lists dividing query elements , : : conditions specify conditions list must met : conditions specify least one conditions list must met : conditions specify none conditions list must met query can constructed writing list entry , like first example. Alternatively, traktok provides convenience functions build query using query_and, query_or, query_not, make building query little easier. can learn https://developers.tiktok.com/doc/research-api-specs-query-videos#query.","code":""},{"path":"https://jbgruber.github.io/traktok/reference/query.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Create a traktok query — query","text":"","code":"if (FALSE) { # using query directly and supplying the list query(or = list( list( field_name = \"hashtag_name\", operation = \"EQ\", field_values = \"rstats\" ), list( field_name = \"keyword\", operation = \"EQ\", field_values = list(\"rstats\", \"API\") ) )) # starting an empty query and building it up using the query_* functions query() |> query_or(field_name = \"hashtag_name\", operation = \"EQ\", field_values = \"rstats\") |> query_or(field_name = \"keyword\", operation = \"IN\", field_values = c(\"rstats\", \"API\")) }"},{"path":[]},{"path":"https://jbgruber.github.io/traktok/reference/tt_comments_api.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Retrieve video comments — tt_comments_api","text":"","code":"tt_comments_api( video_id, fields = \"all\", start_cursor = 0L, max_pages = 1L, cache = TRUE, verbose = TRUE, token = NULL ) tt_comments( video_id, fields = \"all\", start_cursor = 0L, max_pages = 1L, cache = TRUE, verbose = TRUE, token = NULL )"},{"path":"https://jbgruber.github.io/traktok/reference/tt_comments_api.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Retrieve video comments — tt_comments_api","text":"video_id id URL video fields fields returned (defaults ) start_cursor starting cursor, .e., many results skip (picking old search) max_pages results returned batches/pages 100 videos. many requested function stops? cache progress saved current session? can retrieved last_query() error occurs. function use extra memory. verbose function print status updates screen? token authentication token (usually supplied automatically running auth_research )","code":""},{"path":"https://jbgruber.github.io/traktok/reference/tt_comments_api.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Retrieve video comments — tt_comments_api","text":"data.frame parsed comments","code":""},{"path":"https://jbgruber.github.io/traktok/reference/tt_comments_api.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Retrieve video comments — tt_comments_api","text":"","code":"if (FALSE) { tt_comments(\"https://www.tiktok.com/@tiktok/video/7106594312292453675\") # OR tt_comments(\"7106594312292453675\") # OR tt_comments_api(\"7106594312292453675\") }"},{"path":"https://jbgruber.github.io/traktok/reference/tt_get_following_hidden.html","id":null,"dir":"Reference","previous_headings":"","what":"Get followers and following of a user from the hidden API — tt_get_following_hidden","title":"Get followers and following of a user from the hidden API — tt_get_following_hidden","text":"Get 5,000 accounts follow user accounts user follows.","code":""},{"path":"https://jbgruber.github.io/traktok/reference/tt_get_following_hidden.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Get followers and following of a user from the hidden API — tt_get_following_hidden","text":"","code":"tt_get_following_hidden( secuid, sleep_pool = 1:10, max_tries = 5L, cookiefile = NULL, verbose = TRUE ) tt_get_follower_hidden( secuid, sleep_pool = 1:10, max_tries = 5L, cookiefile = NULL, verbose = TRUE ) tt_get_follower( secuid, sleep_pool = 1:10, max_tries = 5L, cookiefile = NULL, verbose = TRUE ) tt_get_following( secuid, sleep_pool = 1:10, max_tries = 5L, cookiefile = NULL, verbose = TRUE )"},{"path":"https://jbgruber.github.io/traktok/reference/tt_get_following_hidden.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Get followers and following of a user from the hidden API — tt_get_following_hidden","text":"secuid secuid user. can get tt_videos querying video account. sleep_pool vector numbers waiting period randomly drawn. max_tries often retry request fails. cookiefile path cookiefile. See vignette(\"unofficial-api\", package = \"traktok\") information authentication. verbose logical. Print status messages.","code":""},{"path":"https://jbgruber.github.io/traktok/reference/tt_get_following_hidden.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Get followers and following of a user from the hidden API — tt_get_following_hidden","text":"data.frame followers","code":""},{"path":"https://jbgruber.github.io/traktok/reference/tt_get_following_hidden.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Get followers and following of a user from the hidden API — tt_get_following_hidden","text":"","code":"if (FALSE) { tt_get_follower_hidden(\"MS4wLjABAAAAun-1Cl5bjjlMXYCkKo58aPekMkPkkFkWB0y0-lSIJ-EMQ_1RLj1slviOVj0Vpuv9\") }"},{"path":"https://jbgruber.github.io/traktok/reference/tt_json.html","id":null,"dir":"Reference","previous_headings":"","what":"Get json file from a TikTok URL — tt_json","title":"Get json file from a TikTok URL — tt_json","text":"function replaced tt_request_hidden().","code":""},{"path":"https://jbgruber.github.io/traktok/reference/tt_json.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Get json file from a TikTok URL — tt_json","text":"","code":"tt_json(...)"},{"path":"https://jbgruber.github.io/traktok/reference/tt_json.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Get json file from a TikTok URL — tt_json","text":"... tt_request_hidden().","code":""},{"path":"https://jbgruber.github.io/traktok/reference/tt_request_hidden.html","id":null,"dir":"Reference","previous_headings":"","what":"Get json string from a TikTok URL using the hidden API — tt_request_hidden","title":"Get json string from a TikTok URL using the hidden API — tt_request_hidden","text":"Use function case want check full data given TikTok video account. tt_videos, opinionated selection data included final object. want different information, can use function.","code":""},{"path":"https://jbgruber.github.io/traktok/reference/tt_request_hidden.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Get json string from a TikTok URL using the hidden API — tt_request_hidden","text":"","code":"tt_request_hidden(url, max_tries = 5L, cookiefile = NULL)"},{"path":"https://jbgruber.github.io/traktok/reference/tt_request_hidden.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Get json string from a TikTok URL using the hidden API — tt_request_hidden","text":"url URL TikTok video account max_tries often retry request fails. cookiefile path cookiefile. See vignette(\"unofficial-api\", package = \"traktok\") information authentication.","code":""},{"path":"https://jbgruber.github.io/traktok/reference/tt_search.html","id":null,"dir":"Reference","previous_headings":"","what":"Search videos — tt_search","title":"Search videos — tt_search","text":"Searches videos using either Research API (authentication token present, see auth_research) otherwise unofficial hidden API. See tt_search_api tt_search_hidden respectively information functions.","code":""},{"path":"https://jbgruber.github.io/traktok/reference/tt_search.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Search videos — tt_search","text":"","code":"tt_search(...)"},{"path":"https://jbgruber.github.io/traktok/reference/tt_search.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Search videos — tt_search","text":"... arguments passed tt_search_api tt_search_hidden","code":""},{"path":"https://jbgruber.github.io/traktok/reference/tt_search.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Search videos — tt_search","text":"data.frame","code":""},{"path":"https://jbgruber.github.io/traktok/reference/tt_search_api.html","id":null,"dir":"Reference","previous_headings":"","what":"Query TikTok videos using the research API — tt_search_api","title":"Query TikTok videos using the research API — tt_search_api","text":"version tt_search explicitly uses Research API. Use tt_search_hidden unofficial API version.","code":""},{"path":"https://jbgruber.github.io/traktok/reference/tt_search_api.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Query TikTok videos using the research API — tt_search_api","text":"","code":"tt_search_api( query, start_date = Sys.Date() - 1, end_date = Sys.Date(), fields = \"all\", start_cursor = 0L, search_id = NULL, is_random = FALSE, max_pages = 1, cache = TRUE, verbose = TRUE, token = NULL ) tt_query_videos( query, start_date = Sys.Date() - 1, end_date = Sys.Date(), fields = \"all\", start_cursor = 0L, search_id = NULL, is_random = FALSE, max_pages = 1, cache = TRUE, verbose = TRUE, token = NULL )"},{"path":"https://jbgruber.github.io/traktok/reference/tt_search_api.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Query TikTok videos using the research API — tt_search_api","text":"query query string object (see query) start_date, end_date start end date narrow search (required). fields fields returned (defaults ) start_cursor starting cursor, .e., many results skip (picking old search) search_id search id (picking old search) is_random Whether query random (defaults FALSE) max_pages results returned batches/pages 100 videos. many requested function stops? cache progress saved current session? can retrieved last_query() error occurs. function use extra memory. verbose function print status updates screen? token authentication token (usually supplied automatically running auth_research )","code":""},{"path":"https://jbgruber.github.io/traktok/reference/tt_search_api.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Query TikTok videos using the research API — tt_search_api","text":"data.frame parsed TikTok videos","code":""},{"path":"https://jbgruber.github.io/traktok/reference/tt_search_api.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Query TikTok videos using the research API — tt_search_api","text":"","code":"if (FALSE) { # look for a keyword or hashtag by default tt_search_api(\"rstats\") # or build a more elaborate query query() |> query_and(field_name = \"region_code\", operation = \"IN\", field_values = c(\"JP\", \"US\")) |> query_or(field_name = \"hashtag_name\", operation = \"EQ\", # rstats is the only hashtag field_values = \"rstats\") |> query_or(field_name = \"keyword\", operation = \"IN\", # rstats is one of the keywords field_values = \"rstats\") |> query_not(operation = \"EQ\", field_name = \"video_length\", field_values = \"SHORT\") |> tt_search_api() # when a search fails after a while, get the results and pick it back up # (only work with same parameters) last_pull <- last_query() query() |> query_and(field_name = \"region_code\", operation = \"IN\", field_values = c(\"JP\", \"US\")) |> query_or(field_name = \"hashtag_name\", operation = \"EQ\", # rstats is the only hashtag field_values = \"rstats\") |> query_or(field_name = \"keyword\", operation = \"IN\", # rstats is one of the keywords field_values = \"rstats\") |> query_not(operation = \"EQ\", field_name = \"video_length\", field_values = \"SHORT\") |> tt_search_api(start_cursor = length(last_pull) + 1, search_id = attr(last_pull, \"search_id\")) }"},{"path":"https://jbgruber.github.io/traktok/reference/tt_search_hidden.html","id":null,"dir":"Reference","previous_headings":"","what":"Search videos — tt_search_hidden","title":"Search videos — tt_search_hidden","text":"version tt_search explicitly uses unofficial API. Use tt_search_api Research API version.","code":""},{"path":"https://jbgruber.github.io/traktok/reference/tt_search_hidden.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Search videos — tt_search_hidden","text":"","code":"tt_search_hidden( query, offset = 0, max_pages = Inf, sleep_pool = 1:10, max_tries = 5L, cookiefile = NULL, verbose = TRUE )"},{"path":"https://jbgruber.github.io/traktok/reference/tt_search_hidden.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Search videos — tt_search_hidden","text":"query query one string offset many videos skip. example, already first X search. max_pages many pages get stopping search. sleep_pool vector numbers waiting period randomly drawn. max_tries often retry request fails. cookiefile path cookiefile. See vignette(\"unofficial-api\", package = \"traktok\") information authentication. verbose logical. Print status messages.","code":""},{"path":"https://jbgruber.github.io/traktok/reference/tt_search_hidden.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Search videos — tt_search_hidden","text":"data.frame","code":""},{"path":"https://jbgruber.github.io/traktok/reference/tt_search_hidden.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Search videos — tt_search_hidden","text":"function wait scraping two videos make less obvious scraper accessing site. period drawn randomly `sleep_pool` multiplied random fraction.","code":""},{"path":"https://jbgruber.github.io/traktok/reference/tt_search_hidden.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Search videos — tt_search_hidden","text":"","code":"if (FALSE) { tt_search_hidden(\"#rstats\", max_pages = 2) }"},{"path":[]},{"path":"https://jbgruber.github.io/traktok/reference/tt_user_info_api.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Lookup TikTok information about a user using the research API — tt_user_info_api","text":"","code":"tt_user_info_api(username, fields = \"all\", verbose = TRUE, token = NULL) tt_user_videos(username, fields = \"all\", verbose = TRUE, token = NULL)"},{"path":"https://jbgruber.github.io/traktok/reference/tt_user_info_api.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Lookup TikTok information about a user using the research API — tt_user_info_api","text":"username name(s) user(s) queried fields fields returned (defaults ) verbose function print status updates screen? token authentication token (usually supplied automatically running auth_research )","code":""},{"path":"https://jbgruber.github.io/traktok/reference/tt_user_info_api.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Lookup TikTok information about a user using the research API — tt_user_info_api","text":"data.frame parsed TikTok videos user posted","code":""},{"path":"https://jbgruber.github.io/traktok/reference/tt_user_info_api.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Lookup TikTok information about a user using the research API — tt_user_info_api","text":"","code":"if (FALSE) { tt_user_info_api(\"jbgruber\") # OR tt_user_info_api(\"https://www.tiktok.com/@tiktok\") # OR tt_user_info(\"https://www.tiktok.com/@tiktok\") }"},{"path":[]},{"path":"https://jbgruber.github.io/traktok/reference/tt_videos_hidden.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Get video metadata and video files from URLs — tt_videos_hidden","text":"","code":"tt_videos_hidden( video_urls, save_video = TRUE, overwrite = FALSE, dir = \".\", cache_dir = NULL, sleep_pool = 1:10, max_tries = 5L, cookiefile = NULL, verbose = TRUE, ... ) tt_videos(...)"},{"path":"https://jbgruber.github.io/traktok/reference/tt_videos_hidden.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Get video metadata and video files from URLs — tt_videos_hidden","text":"video_urls vector URLs TikTok videos. save_video logical. videos downloaded. overwrite logical. save_video=TRUE file already exists, overwritten? dir directory save videos files . cache_dir set path, one RDS file metadata written disk video. useful many videos want pick left something goes wrong. sleep_pool vector numbers waiting period randomly drawn. max_tries often retry request fails. cookiefile path cookiefile. See vignette(\"unofficial-api\", package = \"traktok\") information authentication. verbose logical. Print status messages. ... handed tt_videos_hidden (tt_videos) () tt_request_hidden.","code":""},{"path":"https://jbgruber.github.io/traktok/reference/tt_videos_hidden.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Get video metadata and video files from URLs — tt_videos_hidden","text":"data.frame","code":""},{"path":"https://jbgruber.github.io/traktok/reference/tt_videos_hidden.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Get video metadata and video files from URLs — tt_videos_hidden","text":"function wait scraping two videos make less obvious scraper accessing site. period drawn randomly `sleep_pool` multiplied random fraction. Note video file requested session metadata. URL video file included metadata, link work cases.","code":""},{"path":"https://jbgruber.github.io/traktok/reference/tt_videos_hidden.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Get video metadata and video files from URLs — tt_videos_hidden","text":"","code":"if (FALSE) { tt_videos(\"https://www.tiktok.com/@tiktok/video/7106594312292453675\") }"}]
+[{"path":"https://jbgruber.github.io/traktok/articles/research-api.html","id":"authentication","dir":"Articles","previous_headings":"","what":"Authentication","title":"Research API","text":"get access Research API, need : eligible; create developer account; apply access research API: https://developers.tiktok.com/application/research-api approved client key client secret, can authenticate : recommended run function without arguments, key secret can entered pop mask remain unencrypted R history script. function runs authentication saves resulting token encrypted hard drive. Just run case credentials change.","code":"library(traktok) auth_research()"},{"path":[]},{"path":"https://jbgruber.github.io/traktok/articles/research-api.html","id":"search-videos","dir":"Articles","previous_headings":"Usage","what":"Search Videos","title":"Research API","text":"TikTok uses fine-grained, yet complicated query syntax. convenience, wrapped internally, can search key phrase directly: match keyword phrase keywords hashtags return 200 results (pages 100 results 2 pages requested) today yesterday. Every whitespace treated operator. extend data range, can set start end (can maximum 30 days apart, limit far can go back): said, query syntax TikTok uses little complicated, can use , boolean operators number fields (\"create_date\", \"username\", \"region_code\", \"video_id\", \"hashtag_name\", \"keyword\", \"music_id\", \"effect_id\", \"video_length\"): make easier use, traktok uses tidyverse style approach building queries. example, get query matches #rstats keywords hashtags, need build query like : #rstats found either hashtag keywords video, video returned. Besides checking EQual, can also use one operations: makes building queries relatively complex, allows fine-grained searches TikTok data: return videos posted US Japan, rstats hashtag one keywords length \"MID\", \"LONG\", \"EXTRA_LONG\".1","code":"tt_query_videos(\"#rstats\", max_pages = 2L) #> ℹ Making initial request ✔ Making initial request [734ms] #> ℹ Parsing data ✔ Parsing data [21ms] #> ── search id: NA ─────────────────────────────────────────── #> # A tibble: 0 × 11 #> # ℹ 11 variables: video_id , author_name , #> # view_count , comment_count , #> # region_code , create_time , #> # effect_ids , music_id , #> # video_description , hashtag_names , #> # voice_to_text tt_query_videos(\"#rstats\", max_pages = 2L, start_date = as.Date(\"2023-11-01\"), end_date = as.Date(\"2023-11-29\")) #> ℹ Making initial request ✔ Making initial request [1.1s] #> ℹ Parsing data ✔ Parsing data [30ms] #> ── search id: 7336340473469998126 ────────────────────────── #> # A tibble: 19 × 11 #> video_id author_name view_count comment_count region_code #> #> 1 7306893… statistics… 21 4 DE #> 2 7306307… learningca… 129 12 US #> 3 7305014… picanumeros 57 1 ES #> 4 7302970… smooth.lea… 5568 7 AU #> 5 7302470… statistics… 45 1 DE #> 6 7300977… statistics… 1403 0 DE #> 7 7300931… rigochando 1541 5 MX #> 8 7300922… elartedeld… 87 0 ES #> 9 7299987… statistics… 81 1 DE #> 10 7299657… rigochando 795 5 MX #> 11 7299342… rigochando 375 1 MX #> 12 7298966… rigochando 1183 2 MX #> 13 7296911… biofreelan… 2537 5 MX #> 14 7296911… biofreelan… 1363 0 MX #> 15 7296911… biofreelan… 680 1 MX #> 16 7296688… mrpecners 60 2 US #> 17 7296518… l_a_kelly 10 5 GB #> 18 7296498… mrpecners 19 0 US #> 19 7296288… casaresfel… 266 0 AR #> # ℹ 6 more variables: create_time , #> # effect_ids , music_id , #> # video_description , hashtag_names , #> # voice_to_text query() |> # start by using query() query_or(field_name = \"hashtag_name\", # add an OR condition on the hashtag field operation = \"IN\", # the value should IN the list of hashtags field_values = \"rstats\") |> # the hashtag field does not accept the #-symbol query_or(field_name = \"keyword\", # add another OR condition operation = \"IN\", field_values = \"#rstats\") #> S3 #> └─or: #> ├─ #> │ ├─field_name: \"hashtag_name\" #> │ ├─operation: \"IN\" #> │ └─field_values: #> │ └─\"rstats\" #> └─ #> ├─field_name: \"keyword\" #> ├─operation: \"IN\" #> └─field_values: #> └─\"#rstats\" search_df <- query() |> query_and(field_name = \"region_code\", operation = \"IN\", field_values = c(\"JP\", \"US\")) |> query_or(field_name = \"hashtag_name\", operation = \"EQ\", # rstats is the only hashtag field_values = \"rstats\") |> query_or(field_name = \"keyword\", operation = \"IN\", # rstats is one of the keywords field_values = \"rstats\") |> query_not(operation = \"EQ\", field_name = \"video_length\", field_values = \"SHORT\") |> tt_search_api(start_date = as.Date(\"2023-11-01\"), end_date = as.Date(\"2023-11-29\")) #> ℹ Making initial request ✔ Making initial request [734ms] #> ℹ Parsing data ✔ Parsing data [17ms] search_df #> ── search id: 7336340473470030894 ────────────────────────── #> # A tibble: 2 × 11 #> video_id author_name view_count comment_count region_code #> #> 1 72966888… mrpecners 60 2 US #> 2 72964986… mrpecners 19 0 US #> # ℹ 6 more variables: create_time , #> # effect_ids , music_id , #> # video_description , hashtag_names , #> # voice_to_text "},{"path":"https://jbgruber.github.io/traktok/articles/research-api.html","id":"get-basic-user-information","dir":"Articles","previous_headings":"Usage","what":"Get Basic User Information","title":"Research API","text":"really much getting basic user info, can :","code":"tt_user_info_api(username = c(\"tiktok\", \"https://www.tiktok.com/@statisticsglobe\")) #> # A tibble: 2 × 8 #> display_name follower_count following_count is_verified #> #> 1 TikTok 78785286 30 TRUE #> 2 Statistics Glo… 289 1 FALSE #> # ℹ 4 more variables: likes_count , video_count , #> # avatar_url , bio_description "},{"path":"https://jbgruber.github.io/traktok/articles/research-api.html","id":"obtain-all-comments-of-a-video","dir":"Articles","previous_headings":"Usage","what":"Obtain all Comments of a Video","title":"Research API","text":", much talk comes comments API. need supply video ID, either already: got search: let function extract URL video: essentially . Note, find functionality Research API lacking, nothing keeps using unofficial API functions.","code":"tt_comments_api(video_id = \"7302470379501604128\") #> ℹ Making initial request ✔ Making initial request [7.2s] #> ℹ Parsing data ✔ Parsing data [18ms] #> ── search id: ───────────────────────────────────────────── #> # A tibble: 1 × 7 #> text video_id create_time id like_count #> #> 1 and why would we do… 7302470… 1700243424 7302… 0 #> # ℹ 2 more variables: parent_comment_id , #> # reply_count tt_comments_api(video_id = search_df$video_id[1]) #> ✔ Making initial request [55.7s] #> ℹ Parsing data ✔ Parsing data [18ms] #> ── search id: ───────────────────────────────────────────── #> # A tibble: 2 × 7 #> like_count parent_comment_id reply_count text video_id #> #> 1 1 7296688856609475882 1 So co… 7296688… #> 2 0 7296690681388204831 0 Thank… 7296688… #> # ℹ 2 more variables: create_time , id tt_comments_api(video_id = \"https://www.tiktok.com/@nicksinghtech/video/7195762648716152107?q=%23rstats\") #> ℹ Making initial request ✔ Making initial request [2m 16.7s] #> ℹ Parsing data ✔ Parsing data [19ms] #> ── search id: ───────────────────────────────────────────── #> # A tibble: 96 × 7 #> create_time id like_count parent_comment_id #> #> 1 1675394834 719576596990925… 314 7195762648716152… #> 2 1675457114 719603344301613… 232 7195762648716152… #> 3 1675458796 719604066348022… 177 7195762648716152… #> 4 1675395061 719576692726561… 166 7195765969909252… #> 5 1675624739 719675339339355… 71 7195762648716152… #> 6 1675465779 719607064381200… 71 7195762648716152… #> 7 1675494738 719619490971140… 27 7195762648716152… #> 8 1675691471 719703995331384… 17 7196040663480222… #> 9 1675656122 719688817955866… 16 7195762648716152… #> 10 1675440749 719596313215706… 16 7195762648716152… #> # ℹ 86 more rows #> # ℹ 3 more variables: reply_count , text , #> # video_id "},{"path":"https://jbgruber.github.io/traktok/articles/research-api.html","id":"dealing-with-rate-limits-and-continuing-old-searches","dir":"Articles","previous_headings":"","what":"Dealing with rate limits and continuing old searches","title":"Research API","text":"moment writing vignette, TikTok rate limits Research API follows: Currently, daily limit set 1000 requests per day, allowing obtain 100,000 records per day across APIs. (Video Comments API can return 100 records per request). daily quota gets reset 12 UTC. [Source] Depending like , might enough . case, can actually save search pick back reset. facilitate , search result objects contain two extra pieces information attributes: want continue search, whether rate limit decided want results, can providing search_id cursor tt_search_api. search cut short rate limit another issue, can retrieve results already received search_df <- last_query(). search_df cases contain relevant search_id cursor attributes: Note cursor equal many videos got , API also counts videos “deleted/marked private users etc.” [See max_count Query Videos].","code":"search_df <- query() |> query_and(field_name = \"region_code\", operation = \"IN\", field_values = c(\"JP\", \"US\")) |> tt_search_api(start_date = as.Date(\"2023-11-01\"), end_date = as.Date(\"2023-11-29\"), max_pages = 1) #> ℹ Making initial request ✔ Making initial request [1.9s] #> ℹ Parsing data ✔ Parsing data [20ms] attr(search_df, \"search_id\") #> [1] \"7336340473470063662\" attr(search_df, \"cursor\") #> [1] 100 search_df2 <- query() |> query_and(field_name = \"region_code\", operation = \"IN\", field_values = c(\"JP\", \"US\")) |> tt_search_api(start_date = as.Date(\"2023-11-01\"), end_date = as.Date(\"2023-11-29\"), # this part is new start_cursor = attr(search_df, \"cursor\"), search_id = attr(search_df, \"search_id\"), #### max_pages = 1) #> ℹ Making initial request ✔ Making initial request [5.1s] #> ℹ Parsing data ✔ Parsing data [21ms] attr(search_df2, \"search_id\") #> [1] \"7336340473470063662\" attr(search_df2, \"cursor\") #> [1] 200"},{"path":"https://jbgruber.github.io/traktok/articles/unofficial-api.html","id":"authentication","dir":"Articles","previous_headings":"","what":"Authentication","title":"Unofficial API","text":"easiest way get cookies needed authentication export necessary cookies browser using browser extension (logging TikTok.com least ). can recommend “Get cookies.txt” Chromium based browsers “cookies.txt” Firefox (note almost browsers used today based one ). Save cookies.txt file, look something like : matter download cookies just ones specific TikTok, use cookiemonster package deal . read cookies specific encrypted file, simply use: ’s ! traktok access cookies whenever necessary.","code":"# Netscape HTTP Cookie File # https://curl.haxx.se/rfc/cookie_spec.html # This is a generated file! Do not edit. .tiktok.com TRUE / TRUE 1728810805 cookie-consent {%22ga%22:true%2C%22af%... .tiktok.com TRUE / TRUE 1700471788 passport_csrf_token e07d3487c11ce5258a3... .tiktok.com TRUE / FALSE 1700471788 passport_csrf_token_default e07d3487c11... #HttpOnly_.tiktok.com TRUE / TRUE 1700493610 multi_sids 71573310862246389... #HttpOnly_.tiktok.com TRUE / TRUE 1700493610 cmpl_token AgQQAPORF-RO0rNtH... ... cookiemonster::add_cookies(\"tiktok.com_cookies.txt\")"},{"path":[]},{"path":"https://jbgruber.github.io/traktok/articles/unofficial-api.html","id":"search-videos","dir":"Articles","previous_headings":"Usage","what":"Search videos","title":"Unofficial API","text":"search videos, can use either tt_search tt_search_hidden, , long token Research API. get first two pages search results (one page 12 videos), can use command: already gives pretty much information want videos found.","code":"rstats_df <- tt_search_hidden(\"#rstats\", max_pages = 2) #> ℹ Getting page 1 ⏲ waiting 0.5 seconds ℹ Getting page 1 ✔ Got page 1. Found 12 videos. [1.9s] #> ℹ Getting page 2 ✔ Got page 2. Found 12 videos. [690ms] rstats_df #> # A tibble: 24 × 20 #> video_id video_timestamp video_url video_length video_title #> #> 1 71151144… 2022-06-30 19:17:53 https://… 135 \"R for Beg… #> 2 72522261… 2023-07-05 07:01:45 https://… 36 \"Wow!!! TH… #> 3 72420686… 2023-06-07 22:05:16 https://… 34 \"R GRAPHIC… #> 4 72134135… 2023-03-22 16:49:12 https://… 6 \"R and me … #> 5 72576898… 2023-07-20 00:23:40 https://… 56 \"Pie chart… #> 6 72999870… 2023-11-10 23:58:21 https://… 51 \"Quick R Q… #> 7 72783048… 2023-09-13 13:40:21 https://… 36 \"Quick R Q… #> 8 73029706… 2023-11-19 00:56:09 https://… 163 \"What is c… #> 9 71670108… 2022-11-17 15:42:56 https://… 58 \"Here’s an… #> 10 72933174… 2023-10-24 00:36:48 https://… 9 \"#CapCut #… #> # ℹ 14 more rows #> # ℹ 15 more variables: video_diggcount , #> # video_sharecount , video_commentcount , #> # video_playcount , video_is_ad , author_name , #> # author_nickname , author_followercount