Scrape public TikTok video metadata into JSON Lines files.
Install dependencies:
uv syncRun scripts with:
uv run python <script-name>.pyScrape the default keyword set:
uv run python tiktok_keyword_search.pyScrape specific keywords:
uv run python tiktok_keyword_search.py "україна" "українські новини"Write to a custom output file:
uv run python tiktok_keyword_search.py "ukraine news" -o data/tiktok_videos.jlLimit discovered videos per keyword:
uv run python tiktok_keyword_search.py "ukraine news" --max-videos-per-query 10Scrape direct TikTok video URLs:
uv run python tiktok_keyword_search.py --url "https://www.tiktok.com/@tiktok/video/7655821093684448542"Read keywords or URLs from stdin:
printf '%s\n' "ukraine news" "https://www.tiktok.com/@tiktok/video/7655821093684448542" \
| uv run python tiktok_keyword_search.pyScrape all videos from one account:
uv run python tiktok_account_scraper.py tiktokScrape multiple accounts:
uv run python tiktok_account_scraper.py tiktok nba washingtonpostHandles and profile URLs are also accepted:
uv run python tiktok_account_scraper.py @tiktok "https://www.tiktok.com/@nba"Write to a custom output file:
uv run python tiktok_account_scraper.py tiktok -o data/tiktok_account_videos.jlLimit videos per account:
uv run python tiktok_account_scraper.py tiktok nba --max-videos-per-account 100Read accounts from stdin:
printf '%s\n' tiktok nba washingtonpost \
| uv run python tiktok_account_scraper.pyUse lower concurrency and more delay if TikTok starts rate limiting:
uv run python tiktok_account_scraper.py tiktok \
--concurrency 2 \
--delay 2Change account pagination size:
uv run python tiktok_account_scraper.py tiktok --page-size 20Show all options:
uv run python tiktok_keyword_search.py --help
uv run python tiktok_account_scraper.py --helpSearch a built-in Ukrainian hashtag set:
uv run python tiktok_hashtag_search.pyPreview the Ukrainian hashtags without scraping:
uv run python tiktok_hashtag_search.py --dry-runExtract hashtags from an existing JSON Lines scrape and use them as TikTok search queries:
uv run python tiktok_hashtag_search.py data/tiktok-two.jlWhen an input file is provided, only Ukrainian-looking hashtags are searched by default.
By default this uses the Tikwm search fallback directly with one request at a time, which avoids TikTok search-page discovery stalls.
Preview extracted hashtags without scraping:
uv run python tiktok_hashtag_search.py data/tiktok-two.jl --dry-runSearch every hashtag from an input file, including non-Ukrainian tags:
uv run python tiktok_hashtag_search.py data/tiktok-two.jl --all-file-tagsCombine an input file with the built-in Ukrainian hashtag set:
uv run python tiktok_hashtag_search.py data/tiktok-two.jl --ukrainian-tagsAdd custom tags:
uv run python tiktok_hashtag_search.py --tag київ --tag зсуLimit how many hashtags are searched:
uv run python tiktok_hashtag_search.py data/tiktok-two.jl --max-tags 20Limit videos per hashtag:
uv run python tiktok_hashtag_search.py data/tiktok-two.jl --max-videos-per-tag 10Use the full TikTok search cascade from tiktok_keyword_search.py:
uv run python tiktok_hashtag_search.py data/tiktok-two.jl --backend fullWrite hashtag search results to a custom output file:
uv run python tiktok_hashtag_search.py data/tiktok-two.jl -o data/tiktok_hashtag_videos.jlScrape Instagram Reels from public search discovery:
uv run python instagram_reels_search.py "ukraine news"Scrape direct Instagram Reel URLs:
uv run python instagram_reels_search.py --url "https://www.instagram.com/reel/Ch74NvrD2UV/"Write to a custom output file:
uv run python instagram_reels_search.py "ukraine news" -o data/instagram_reels.jlLimit discovered Reels per query:
uv run python instagram_reels_search.py "ukraine news" --max-reels-per-query 10Instagram keyword discovery uses a text mirror of public search results, then follows discovered Reel URLs and extracts Open Graph metadata. Direct Reel URLs and account scraping are also supported.
Scrape Reels/video nodes from one account:
uv run python instagram_account_scraper.py instagramScrape multiple accounts:
uv run python instagram_account_scraper.py instagram natgeoHandles and profile URLs are also accepted:
uv run python instagram_account_scraper.py @instagram "https://www.instagram.com/natgeo/"Limit Reels per account:
uv run python instagram_account_scraper.py instagram --max-reels-per-account 25Write to a custom output file:
uv run python instagram_account_scraper.py instagram -o data/instagram_account_reels.jlRead accounts from stdin:
printf '%s\n' instagram natgeo \
| uv run python instagram_account_scraper.pyExtract hashtags from an existing JSON Lines scrape and use them as Instagram Reel search queries:
uv run python instagram_hashtag_search.py data/tiktok-two.jlPreview extracted hashtags without scraping:
uv run python instagram_hashtag_search.py data/tiktok-two.jl --dry-runLimit hashtags and Reels per hashtag:
uv run python instagram_hashtag_search.py data/tiktok-two.jl \
--max-tags 20 \
--max-reels-per-tag 5Write hashtag search results to a custom output file:
uv run python instagram_hashtag_search.py data/tiktok-two.jl -o data/instagram_hashtag_reels.jlOutputs are JSON Lines files. Each line is one video record with fields like:
{
"source_url": "https://www.tiktok.com/@tiktok/video/7655821093684448542",
"scraped_at": "2026-06-26T22:39:44.057340+00:00",
"id": "7655821093684448542",
"description": "Video caption text",
"created_at": 1782509772,
"author": {},
"stats": {},
"video": {},
"music": {},
"hashtags": []
}Default output paths:
data/tiktok_videos.jl
data/tiktok_account_videos.jl
data/instagram_reels.jl
data/instagram_account_reels.jl
data/instagram_hashtag_reels.jl