Ważne zastrzeżenie: Ten artykuł dotyczy wyłącznie dostępu do publicznie dostępnych danych, które nie wymagają logowania. Należy przestrzegać Warunków Użytkowania TikTok oraz obowiązujących przepisów prawa, w tym RODO w UE i CFAA w USA. Nieautoryzowany dostęp do danych niepublicznych lub omijanie zabezpieczeń w celu uzyskania danych chronionych jest nielegalne. Zawsze rozważ użycie oficjalnego API TikTok, gdy jest dostępne.
Dlaczego scrapowanie TikTok jest trudne?
TikTok należy do najtrudniejszych platform do scrapowania. ByteDance, właściciel TikTok, zainwestował ogromne środki w rozbudowaną infrastrukturę anti-bot, która łączy tradycyjne zabezpieczenia WAF z własnym, zastrzeżonym stosem detekcji. Dla zespołów analitycznych i deweloperów budujących narzędzia dla ekonomii twórców, zrozumienie tych mechanizmów jest kluczowe.
TikTok to platforma mobile-first — większość użytkowników korzysta z niej na urządzeniach mobilnych. Oznacza to, że każdy ruch pochodzący z „desktopowego” klienta jest natychmiast podejrzany. Platforma aktywnie blokuje:
- Automatyczne przeglądarki — Playwright, Puppeteer, Selenium są wykrywane przez analizę odcisków palca przeglądarki.
- Znane adresy IP datacenter — TikTok utrzymuje bazy IP hostingów i VPN-ów.
- Nietypowe wzorce ruchu — zbyt wiele żądań z jednego IP lub konta.
- Niespójne nagłówki i sygnatury — brak lub nieprawidłowe parametry
_signatureimsToken.
Stos detekcji ByteDance
ByteDance stosuje wielowarstwowe podejście do detekcji botów:
- WAF (Web Application Firewall) — filtruje ruch na poziomie sieciowym, blokując znane wzorce botów.
- Weryfikacja urządzenia — TikTok zbiera tysiące punktów danych o urządzeniu: model, system operacyjny, rozdzielczość ekranu, zainstalowane czcionki, rozszerzenia WebGL i wiele innych.
- Podpisywanie żądań — każde żądanie API musi zawierać poprawny parametr
_signaturegenerowany przez zastrzeżony kod JavaScript. - Tokeny sesji —
msTokeni inne tokeny śledzą spójność sesji. - Analiza behawioralna — TikTok monitoruje wzorce interakcji: ruchy myszy, tempo przewijania, czas na stronie.
Jakie dane publiczne są dostępne bez logowania?
TikTok udostępnia znaczną ilość danych bez wymagania logowania. Są to dane widoczne dla każdego odwiedzającego platformę:
| Typ danych | URL | Dostępne pola | Trudność scrapowania |
|---|---|---|---|
| Profil twórcy | tiktok.com/@username |
Nazwa, bio, liczba obserwujących, liczba polubień, lista filmów | Średnia |
| Strona filmu | tiktok.com/@username/video/ID |
Tytuł, opis, tagi, liczba wyświetleń, polubień, komentarzy, udostępnień | Średnia |
| Strona hashtag | tiktok.com/tag/hashtag |
Lista filmów, liczba użyczeń, trendy | Wysoka |
| Trending | tiktok.com/foryou |
Filmy na stronie „Dla Ciebie” | Bardzo wysoka |
| Wyniki wyszukiwania | tiktok.com/search?q=query |
Filmy, użytkownicy, hashtagi pasujące do zapytania | Bardzo wysoka |
Strony profilu twórców i poszczególnych filmów są relatywnie łatwiejsze do scrapowania — wymagają podstawowej emulacji przeglądarki i proxy. Strony hashtagów, trending i wyniki wyszukiwania są znacznie bardziej chronione i wymagają zaawansowanych technik.
Dlaczego proxy rezydencjalne z IP mobilnymi są najlepsze?
TikTok jest platformą mobile-first — ponad 80% ruchu pochodzi z aplikacji mobilnej. Oznacza to, że ruch z adresów IP desktopowych lub datacenter jest natychmiast podejrzany dla algorytmów detekcji.
Porównanie typów proxy dla TikTok
| Typ proxy | Wykrywalność | Koszt | Zalecenie |
|---|---|---|---|
| Datacenter | Bardzo wysoka — łatwo blokowane | Niski | Nie zalecane |
| Rezydencjalne (desktop) | Średnia — wygląda jak ruch domowy | Średni | Dobre do podstawowego scrapowania |
| Rezydencjalne (mobile) | d>Niska — wygląda jak ruch z aplikacjiWysoki | Najlepsze dla TikTok |
Proxy rezydencjalne mobilne (mobile residential) pochodzą z rzeczywistych urządzeń mobilnych — smartfonów i tabletów z legalnymi operatorami komórkowymi. Dla TikTok ruch z takich IP wygląda jak ruch prawdziwego użytkownika korzystającego z aplikacji mobilnej.
Przy konfiguracji proxy dla TikTok warto zastosować:
- Rotacja per sesja — utrzymanie jednego IP dla całej sesji scrapowania poprawia wiarygodność.
- Geo-targeting — używanie IP z tego samego kraju co docelowa zawartość.
- Sticky sessions — TikTok śledzi spójność sesji; nagłe zmiany IP mogą wywołać CAPTCHA.
Podstawowa konfiguracja proxy z ProxyHat
Dla scrapowania TikTok zalecamy proxy rezydencjalne z flagą mobilną. Przykładowa konfiguracja:
# HTTP proxy z geo-targetingiem (USA, mobile)
http://user-country-US-mobile-true:PASSWORD@gate.proxyhat.com:8080
# SOCKS5 proxy z sesją sticky
socks5://user-country-US-mobile-true-session-abc123:PASSWORD@gate.proxyhat.com:1080
# Geo-targeting na poziomie miasta
http://user-country-US-city-newyork-mobile-true:PASSWORD@gate.proxyhat.com:8080
Parametr mobile-true zapewnia, że otrzymasz adres IP z puli mobilnej, co jest kluczowe dla TikTok.
Python + Playwright: Przykład implementacji
Poniżej przedstawiam kompletny przykład scrapowania profilu twórcy TikTok przy użyciu Playwright z trybem stealth i proxy rezydencjalnym:
import asyncio
import json
from playwright.async_api import async_playwright
# Konfiguracja proxy ProxyHat
PROXY_CONFIG = {
"server": "http://gate.proxyhat.com:8080",
"username": "user-country-US-mobile-true",
"password": "TWOJE_HASLO"
}
# Emulacja urządzenia mobilnego (iPhone 14 Pro)
MOBILE_DEVICE = {
"user_agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 TikTok/28.0.0",
"viewport": {"width": 393, "height": 852},
"device_scale_factor": 3,
"is_mobile": True,
"has_touch": True
}
async def scrape_tiktok_profile(username: str):
async with async_playwright() as p:
# Uruchomienie przeglądarki z proxy i emulacją mobilną
browser = await p.chromium.launch(
proxy=PROXY_CONFIG,
headless=True,
args=[
"--disable-blink-features=AutomationControlled",
"--disable-features=IsolateOrigins,site-per-process"
]
)
context = await browser.new_context(
user_agent=MOBILE_DEVICE["user_agent"],
viewport=MOBILE_DEVICE["viewport"],
device_scale_factor=MOBILE_DEVICE["device_scale_factor"],
is_mobile=MOBILE_DEVICE["is_mobile"],
has_touch=MOBILE_DEVICE["has_touch"],
# Dodatkowe nagłówki mobilne
extra_http_headers={
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
"Accept-Encoding": "gzip, deflate, br",
"Connection": "keep-alive"
}
)
# Wstrzyknięcie skryptów anti-detection
await context.add_init_script("""
Object.defineProperty(navigator, 'webdriver', {get: () => undefined});
Object.defineProperty(navigator, 'platform', {get: () => 'iPhone'});
window.chrome = {runtime: {}};
Object.defineProperty(navigator, 'plugins', {get: () => [1, 2, 3, 4, 5]});
Object.defineProperty(navigator, 'languages', {get: () => ['en-US', 'en']});
""")
page = await context.new_page()
try:
# Nawigacja do profilu
url = f"https://www.tiktok.com/@{username}"
await page.goto(url, wait_until="networkidle", timeout=30000)
# Czekanie na załadowanie danych
await page.wait_for_selector('[data-e2e="user-post-item"]', timeout=15000)
# Ekstrakcja danych profilu
profile_data = await page.evaluate("""
() => {
const stats = document.querySelectorAll('[data-e2e^="followers-count"]');
return {
username: window.location.pathname.split('/')[1].replace('@', ''),
followers: stats[0]?.textContent || null,
following: stats[1]?.textContent || null,
likes: stats[2]?.textContent || null,
bio: document.querySelector('[data-e2e="profile-bio"]')?.textContent || null
};
}
""")
# Scrollowanie dla załadowania filmów
videos = []
for _ in range(3): # Scroll 3 razy
await page.evaluate("window.scrollTo(0, document.body.scrollHeight)")
await page.wait_for_timeout(2000)
# Ekstrakcja filmów
video_elements = await page.query_selector_all('[data-e2e="user-post-item"]')
for video in video_elements[:10]: # Pierwsze 10 filmów
link = await video.query_selector('a')
href = await link.get_attribute('href')
views = await video.query_selector('[data-e2e="video-views"]')
videos.append({
"url": href,
"views": await views.inner_text() if views else None
})
profile_data["videos"] = videos
return profile_data
except Exception as e:
print(f"Błąd scrapowania: {e}")
return None
finally:
await browser.close()
# Uruchomienie
result = asyncio.run(scrape_tiktok_profile("example_creator"))
print(json.dumps(result, indent=2, ensure_ascii=False))
Kluczowe elementy tego kodu
- Emulacja urządzenia mobilnego — pełna konfiguracja viewport, user-agent i nagłówków dla iPhone.
- Skrypty anti-detection — nadpisanie właściwości
navigator.webdriveri innych wskaźników automatyzacji. - Proxy rezydencjalne — użycie ProxyHat z flagą
mobile-true. - Wstrzymanie dla networkidle — czekanie na pełne załadowanie strony przed ekstrakcją.
Obsługa parametru _signature
TikTok podpisuje żądania API przy użyciu zastrzeżonego algorytmu. Parametr _signature jest generowany przez JavaScript wykonywany w przeglądarce i jest wymagany dla większości żądań API. Bez poprawnego podpisu serwery TikTok odrzucają żądanie.
Jak działa podpisywanie żądań TikTok
TikTok używa skomplikowanego mechanizmu podpisywania, który:
- Generuje unikalny token sesji (
msToken). - Tworzy skrót (hash) z parametrów żądania, timestampu i tajnego klucza.
- Podpisuje wynik przy użyciu algorytmu podobnego do HMAC.
- Koduje wynik w formacie URL-safe base64.
Algorytm jest zastrzeżony i często zmieniany przez ByteDance, co czyni inżynierię wsteczną trudną i nietrwałą.
Podejścia do obsługi _signature
| Metoda | Zalety | Wady | Zalecenie |
|---|---|---|---|
| Playwright JS execution | Bezpieczne, używa oficjalnego kodu TikTok | Wymaga pełnej przeglądarki, wolniejsze | Dobre dla małej skali |
| Serwisy podpisujące (third-party) | Szybkie, nie wymaga przeglądarki | Kosztowne, zależność od zewnętrznego dostawcy | Dobre dla dużej skali |
| Inżynieria wsteczna | Pełna kontrola, brak zależności | Bardzo trudne, wymaga ciągłej aktualizacji | Tylko dla zaawansowanych |
| Scrapowanie HTML zamiast API | Unika potrzeby podpisu API | Mniej danych, wolniejsze | Zalecane na start |
Przykład ekstrakcji _signature przez Playwright
async def get_tiktok_signature(page, url: str) -> str:
"""Ekstrakcja podpisu z wykonanego żądania TikTok"""
signature = None
async def capture_signature(request):
nonlocal signature
if "api/tiktok" in request.url or "/api/" in request.url:
params = request.url.split("?")[-1]
if "_signature" in params:
# Parsowanie parametrów URL
for param in params.split("&"):
if param.startswith("_signature="):
signature = param.split("=")[1]
page.on("request", capture_signature)
# Nawigacja i wywołanie żądania
await page.goto(url)
await page.wait_for_timeout(3000)
return signature
Dla zastosowań produkcyjnych zalecamy jednak scrapowanie warstwy HTML zamiast API — jest bardziej stabilne i nie wymaga inżynierii podpisów.
Node.js: Alternatywna implementacja
Dla zespołów używających Node.js, oto odpowiednia implementacja:
const { chromium } = require('playwright');
const PROXY_CONFIG = {
server: 'http://gate.proxyhat.com:8080',
username: 'user-country-US-mobile-true',
password: 'TWOJE_HASLO'
};
const MOBILE_USER_AGENT = 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) ' +
'AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 TikTok/28.0.0';
async function scrapeTikTokHashtag(hashtag) {
const browser = await chromium.launch({
proxy: PROXY_CONFIG,
headless: true,
args: ['--disable-blink-features=AutomationControlled']
});
const context = await browser.newContext({
userAgent: MOBILE_USER_AGENT,
viewport: { width: 393, height: 852 },
isMobile: true,
hasTouch: true
});
// Anti-detection
await context.addInitScript(`
Object.defineProperty(navigator, 'webdriver', {get: () => undefined});
window.chrome = {runtime: {}};
`);
const page = await context.newPage();
try {
await page.goto(`https://www.tiktok.com/tag/${hashtag}`, {
waitUntil: 'networkidle',
timeout: 30000
});
// Czekanie na filmy
await page.waitForSelector('[data-e2e="search-video-item"]', {
timeout: 15000
});
// Scrollowanie dla więcej wyników
for (let i = 0; i < 5; i++) {
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
await page.waitForTimeout(1500);
}
// Ekstrakcja danych
const videos = await page.$$eval(
'[data-e2e="search-video-item"]',
(items) => items.slice(0, 20).map(item => ({
url: item.querySelector('a')?.href,
title: item.querySelector('[data-e2e="search-video-desc"]')?.textContent,
author: item.querySelector('[data-e2e="search-video-author"]')?.textContent
}))
);
return { hashtag, videos, count: videos.length };
} finally {
await browser.close();
}
}
// Użycie
scrapeTikTokHashtag('prank').then(console.log);
Wzorce skalowania dla analityki twórców
Dla zespołów budujących narzędzia analityczne dla ekonomii twórców, oto sprawdzone wzorce skalowania:
1. Śledzenie profilu twórcy (Creator Tracking)
Regularne scrapowanie profili twórców pozwala śledzić wzrost obserwujących, trendy w treściach i engagement rate.
import asyncio
from datetime import datetime
import json
CREATORS = [
"charlidamelio",
"khaby.lame",
"bellapoarch",
"addisonre"
]
async def track_creators():
results = []
for creator in CREATORS:
data = await scrape_tiktok_profile(creator)
if data:
data["scraped_at"] = datetime.now().isoformat()
results.append(data)
# Opóźnienie między twórcami
await asyncio.sleep(5)
return results
# Harmonogram: uruchom co 6 godzin z różnymi sesjami proxy
2. Wykrywanie trendów (Trend Detection)
Monitorowanie hashtagów i trending page pozwala identyfikować viral content przed konkurencją.
TRENDING_HASHTAGS = ["fyp", "viral", "trending", "foryou"]
async def detect_trends():
trends = []
for tag in TRENDING_HASHTAGS:
data = await scrape_tiktok_hashtag(tag)
if data:
# Analiza najpopularniejszych filmów
top_videos = sorted(
data["videos"],
key=lambda x: x.get("views", 0),
reverse=True
)[:5]
trends.append({
"hashtag": tag,
"top_videos": top_videos,
"scraped_at": datetime.now().isoformat()
})
return trends
3. Monitorowanie hashtagów (Hashtag Monitoring)
Dla marek i agencji monitorowanie hashtagów związanych z kampaniami jest kluczowe.
async def monitor_brand_hashtags(brand_tags: list):
"""Monitorowanie hashtagów związanych z marką"""
results = []
# Użycie różnych proxy dla każdego hashtagu
for i, tag in enumerate(brand_tags):
# Rotacja sesji co 5 hashtagów
session_id = f"session-{i // 5}"
proxy_url = f"http://user-country-US-mobile-true-session-{session_id}:PASSWORD@gate.proxyhat.com:8080"
data = await scrape_tiktok_hashtag(tag, proxy=proxy_url)
results.append(data)
# Rate limiting
await asyncio.sleep(3)
return results
Limitowanie szybkości i obsługa błędów
TikTok agresywnie limituje żądania. Oto najlepsze praktyki:
- Maksymalnie 30-50 żądań na godzinę z jednego IP dla scrapowania HTML.
- Rotacja sesji proxy — używaj sticky sessions i zmieniaj sesję co 50-100 żądań.
- Randomizacja opóźnień — dodaj losowe opóźnienia 2-5 sekund między żądaniami.
- Obsługa CAPTCHA — przy wykryciu CAPTCHA, zmień IP i spróbuj ponownie.
- Retry z exponential backoff — przy błędach 429, czekaj z rosnącym czasem.
import random
import time
from functools import wraps
def rate_limit(func):
@wraps(func)
async def wrapper(*args, **kwargs):
max_retries = 3
for attempt in range(max_retries):
try:
result = await func(*args, **kwargs)
# Randomizacja opóźnienia
await asyncio.sleep(random.uniform(2, 5))
return result
except Exception as e:
if "429" in str(e) or "rate" in str(e).lower():
wait_time = (2 ** attempt) + random.uniform(0, 1)
print(f"Rate limit, czekam {wait_time}s...")
await asyncio.sleep(wait_time)
else:
raise e
return None
return wrapper
Kiedy używać oficjalnego API TikTok?
TikTok oferuje oficjalne API Research i Display Kit, które może być odpowiednie dla niektórych zastosowań:
| Aspekt | Oficjalne API | Scrapowanie |
|---|---|---|
| Dostępność danych | Ograniczone, wymaga zgody twórcy | Wszystkie dane publiczne |
| Stabilność | Wysoka, udokumentowane | Niska, wymaga utrzymania |
| Koszt | Darmowe lub płatne (zależnie od planu) | Koszt proxy i infrastruktury |
| Rate limits | Ścisłe limity | Ograniczone tylko przez detekcję |
| Legalność | Pełna zgodność z ToS | Szare prawne, wymaga ostrożności |
Zalecenie: Dla zastosowań komercyjnych wymagających stabilności i zgodności, rozważ najpierw oficjalne API. Dla badań, analizy trendów i prototypowania, scrapowanie z odpowiednimi proxy może być bardziej praktyczne.
Etyczne scrapowanie i najlepsze praktyki
Scrapowanie danych publicznych jest legalne w wielu jurysdykcjach, ale wymaga przestrzegania pewnych zasad:
- Szanuj robots.txt — sprawdź, czy platforma wyraźnie zabrania scrapowania.
- Nie obciążaj infrastruktury — używaj rozsądnych rate limits.
- Nie omijaj płatnych ścian — scrapuj tylko dane dostępne bez logowania.
- Szanuj prywatność — nie gromadź danych osobowych bez potrzeby.
- Rozważ RODO/CCPA — dane użytkowników podlegają ochronie.
- Używaj danych odpowiedzialnie — nie do spamu, manipulacji ani naruszeń.
Kluczowe wnioski: Scrapowanie TikTok wymaga proxy rezydencjalnych mobilnych, pełnej emulacji urządzenia mobilnego i ostrożności przy podpisywaniu żądań. Dla najlepszych rezultatów scrapuj warstwę HTML zamiast API, używaj sticky sessions i limituj żądania do 30-50 na godzinę na IP. Zawsze rozważ oficjalne API dla zastosowań produkcyjnych.
Podsumowanie
Scrapowanie publicznych danych TikTok jest możliwe, ale wymaga zaawansowanych technik: proxy rezydencjalnych mobilnych, emulacji urządzeń mobilnych, obsługi anti-detection i ostrożnego podejścia do rate limiting. Dla zespołów analitycznych i deweloperów budujących narzędzia dla ekonomii twórców, proxy mobilne od ProxyHat zapewniają niezbędną wiarygodność ruchu.
Kluczowe elementy skutecznego scrapowania TikTok to:
- Użycie proxy rezydencjalnych mobilnych z odpowiednim geo-targetingiem.
- Pełna emulacja urządzenia mobilnego w Playwright lub Puppeteer.
- Skrypty anti-detection dla ukrycia automatyzacji.
- Rozsądne rate limiting i rotacja sesji.
- Preferowanie scrapowania HTML nad API.
Dla bardziej stabilnych zastosowań produkcyjnych, zawsze rozważ oficjalne API TikTok lub skonsultuj się z prawnikiem w kwestii zgodności z lokalnymi przepisami.
Zobacz cennik ProxyHat aby rozpocząć z proxy rezydencjalnymi mobilnymi dla TikTok.






