This is Part 2 of the series.
Part 1 covered extracting profile data and video lists (via HasData + TikTok endpoints). Here, we’ll use those results to download videos.
Table of Contents
Requirements
You’ll need:
- Python 3.8+
- requests
- HasData API key (if you want to refresh links)
pip install requests
Basic downloader
Simple, memory-safe way to download each video file in chunks.
import json
import requests
import os
import time
DOWNLOAD_FOLDER = "tiktok_videos"
os.makedirs(DOWNLOAD_FOLDER, exist_ok=True)
HEADERS = {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
"accept": "*/*",
"referer": "https://www.tiktok.com",
}
def download_video(url, filepath):
try:
with requests.get(url, headers=HEADERS, stream=True, timeout=30) as r:
r.raise_for_status()
with open(filepath, "wb") as f:
for chunk in r.iter_content(chunk_size=8192):
if chunk:
f.write(chunk)
print(f"[OK] {filepath}")
return True
except requests.HTTPError as e:
print(f"[HTTP {e.response.status_code}] {filepath}")
return False
except Exception as e:
print(f"[ERROR] {filepath}: {e}")
return False
# Load video list from Part 1
with open("videos_clean_full.json", "r", encoding="utf-8") as f:
videos = json.load(f)
for video in videos:
vid = video.get("id")
url = video.get("downloadAddr")
if not url:
print(f"[WARN] No link for {vid}")
continue
path = os.path.join(DOWNLOAD_FOLDER, f"{vid}.mp4")
if os.path.exists(path):
print(f"[SKIP] {vid}")
continue
download_video(url, path)
time.sleep(0.5)
This handles streaming, writes to disk in chunks, and skips existing files.
Handling expired links
TikTok download links expire fast. If you reuse old links, you’ll get 403 Forbidden. When that happens, request a fresh link using HasData.
from bs4 import BeautifulSoup
import json
def refresh_download_url(video_page_url, api_key, country="DE"):
api_url = "https://api.hasdata.com/scrape/web"
payload = {
"url": video_page_url,
"proxyType": "residential",
"proxyCountry": country,
"blockResources": False,
"wait": 1000,
"jsRendering": True
}
headers = {
"Content-Type": "application/json",
"x-api-key": api_key
}
try:
r = requests.post(api_url, headers=headers, json=payload, timeout=30)
r.raise_for_status()
data = r.json()
html = data.get("content")
if not html:
return None
soup = BeautifulSoup(html, "html.parser")
script = soup.find("script", id="__UNIVERSAL_DATA_FOR_REHYDRATION__")
if not script or not script.string:
return None
raw = json.loads(script.string)
items = raw.get("__DEFAULT_SCOPE__", {}).get("webapp.video-detail", {}).get("itemModule", {})
for v in items.values():
d = v.get("video", {}).get("downloadAddr")
if d:
return d
except Exception as e:
print(f"[ERROR] refresh: {e}")
return None
Retry failed downloads and refresh URLs on 403.
MAX_RETRIES = 3
HASDATA_API_KEY = "YOUR-API-KEY"
for v in videos:
vid = v.get("id")
url = v.get("downloadAddr")
page = f"https://www.tiktok.com/@funny_funny66066/video/{vid}"
path = os.path.join(DOWNLOAD_FOLDER, f"{vid}.mp4")
attempts = 0
while attempts < MAX_RETRIES:
ok = download_video(url, path)
if ok:
break
attempts += 1
print(f"[RETRY] {vid} ({attempts}) — refreshing URL")
url = refresh_download_url(page, HASDATA_API_KEY) or url
time.sleep(1)
if not ok:
print(f"[FAIL] {vid}")
Notes
More useful resources:
Top comments (3)
The expired-link issue is probably one of the biggest things to account for when building a TikTok downloader this way. A direct
downloadAddrisn't necessarily something you can treat as a permanent file URL, so refreshing it when you receive a 403 makes sense.The Python approach is especially useful when you're downloading a larger set of videos or want the whole process automated. For someone who only needs to save an occasional public TikTok video, though, setting up Python, API access, scraping and URL refreshing can be overkill. In that case, a browser-based option such as Clipzun can be more convenient since you can simply provide the video URL and download it without setting up a development environment.
So I'd see these as two different use cases rather than competing approaches: Python for automation and batch workflows, and a web-based Video Downloader for quick individual downloads.
Some comments may only be visible to logged-in visitors. Sign in to view all comments.