Temu nie udostępnia publicznego API, a jego katalog produktów i cen jest dynamicznie renderowany przez Next.js z silną warstwą anti-bot. Jeśli chcesz scrapować Temu w 2026 roku w sposób stabilny i powtarzalny, musisz wybrać między parsowaniem podatnego na zmiany HTML a odpytywaniem wewnętrznych endpointów JSON takich jak /api/poppy/v1/search i /api/poppy/v1/goods-detail. Ten przewodnik pokazuje, jak to zrobić z proxy rezydencyjnymi ProxyHat, jak zachować spójność sesji i jak unikać blokad bez psucia warunków korzystania z serwisu.
Dlaczego scrapowanie Temu jest trudne — kontekst techniczny
Temu to marketplace należący do PDD Holdings, zbudowany na stosie Next.js z warstwą CDN Cloudflare. Architektura renderowania sprawia, że klasyczne podejście „pobierz HTML i wyciągnij selektory CSS” bywa zawodne: karty produktów są hydratowane z osadzonego blobu stanu, a wiele elementów ma hashowane klasy CSS (np. _2q1tC7w), które zmieniają się między buildami. Dodatkowo ceny, dostępność i koszty wysyłki różnią się w zależności od regionu i sesji użytkownika, co oznacza, że adres IP i nagłówki geolokalizacyjne wpływają na to, co faktycznie zobaczysz.
Największe wyzwanie to jednak warstwa anti-bot. Temu korzysta z Cloudflare Turnstile oraz własnego podpisanego nagłówka anti_content, który zawiera token generowany po stronie klienta na podstawie zachowania, fingerprintu przeglądarki i danych środowiskowych. Brak lub nieprawidłowa wartość tego nagłówka powoduje natychmiastowe odrzucenie żądania. Dodatkowo Cloudflare wykonuje fingerprinting TLS i HTTP/2 — datacenterowe adresy IP są flagowane niemal natychmiast, zanim jeszcze dotrzesz do logiki aplikacji Temu.
To, że możesz otworzyć stronę w przeglądarce, nie oznacza, że Twoje żądanie z biblioteki requests przejdzie. Temu bada nie tylko nagłówki, ale też zachowanie TLS, kolejność ramek HTTP/2 i reputację IP.
HTML vs JSON — wybór strategii
Pierwszą decyzją jest to, czy parsować HTML kart produktów, czy uderzać w endpointy JSON. Parsowanie HTML wydaje się prostsze, ale jest kruche: hashowane klasy CSS zmieniają się co kilka tygodni, a struktura DOM zależy od testów A/B. Endpointy JSON są stabilniejsze semantycznie, ale wymagają prawidłowego anti_content i innych nagłówów autoryzacyjnych.
| Podejście | Stabilność | Koszty implementacji | Wrażliwość na anti-bot |
|---|---|---|---|
| Parsowanie HTML kart | Niska — hashowane klasy | Niska na start, wysoka w utrzymaniu | Wysoka (Turnstile + TLS) |
| Endpointy JSON (poppy/v1) | Średnia-wysoka | Wysoka na start (anti_content) | Wysoka, ale bardziej przewidywalna |
| Osadzony blob stanu (Next.js) | Średnia | Średnia | Średnia |
W praktyce hybryda często sprawdza się najlepiej: pobierasz pełną stronę produktu, wyciągasz osadzony blob stanu (odpowiednik __NEXT_DATA__), a dla paginacji i wyszukiwania odpytujesz endpointy JSON z tym samym tokenem anti_content, który udało Ci się zdobyć.
Stack anti-bot Temu — co musisz wiedzieć
Cloudflare Turnstile i podpisany anti_content
Turnstile to niewidoczne wyzwanie, które analizuje sygnały behawioralne i środowiskowe. W przypadku Temu dochodzi do tego nagłówek anti_content, który jest tokenem generowanym przez kod JavaScript po stronie klienta. Token zawiera zaszyty podpis na podstawie m.in. navigator.userAgent, screen.width, performance.timing i innych właściwości. Bez poprawnego tokena endpointy JSON zwracają błąd lub pusty wynik.
Praktyczne podejście to uruchomienie prawdziwej przeglądarki (Playwright, Puppeteer) raz na sesję, pobranie ciasteczek i nagłówka anti_content, a następnie użycie tych danych w lżejszych żądaniach HTTP. To zmniejsza zużycie zasobów i pozwala na paginację bez każdorazowego renderowania strony.
Fingerprinting TLS/HTTP2 i reputacja IP
Cloudflare klasyfikuje klienty na podstawie JA3/JA4 oraz ustawień HTTP/2 (np. SETTINGS_MAX_CONCURRENT_STREAMS, kolejności nagłówków). Biblioteki takie jak Python requests mają fingerprint znacznie różniący się od Chrome, co jest sygnałem alarmowym. Dlatego w przykładach poniżej używamy curl_cffi, który emuluje fingerprint TLS przeglądarki Chrome.
Reputacja IP jest równie ważna. Datacenterowe bloki IP są często na listach Cloudflare jako „boty”. Proxy rezydencyjne z prawdziwych ISP są trudniejsze do odróżnienia od zwykłych użytkowników, co jest kluczowe, gdy ceny i dostępność zależą od regionu.
Lokalizowanie danych — blob stanu i atrybuty data-uniqid
Na stronie produktu Temu osadza duży blob JSON w tagu <script id="__NEXT_DATA__" type="application/json"> (lub podobnym, zależnie od buildu). Zawiera on pełną strukturę produktu: goods_id, goods_name, listę SKU, ceny, atrybuty i obrazy. Wyciągnięcie go jest szybsze i stabilniejsze niż parsowanie DOM.
W przypadku kart na stronie wyszukiwania przydatne są atrybuty data-uniqid na elementach kart, które mapują się do goods_id. Pozwala to na szybkie zbudowanie listy ID do dalszego odpytywania endpointu /api/poppy/v1/goods-detail.
Przykładowy wzorzec XPath dla ID produktu
//div[contains(@class, 'goods-list')]
//div[@data-uniqid]/@data-uniqid
Pamiętaj, że hashowane klasy mogą się zmienić — traktuj goods-list jako heurystykę, a nie pewnik.
Rate-limit i dlaczego proxy rezydencyjne są obowiązkowe
Temu nie publikuje oficjalnych progów rate-limit, ale empiryczne obserwacje wskazują, że z jednego adresu IP można wykonać około 30–60 żądań na minutę do endpointów JSON, zanim pojawi się błąd 403 lub wyzwanie Turnstile. Przy agresywniejszym tempie (np. 1500 żądań na minutę) blokada następuje niemal natychmiast. Dlatego rotacja IP i kontrola współbieżności są kluczowe.
Drugim powodem jest geolokalizacja. Ceny, dostępność i koszty wysyłki na Temu różnią się w zależności od kraju, a nawet stanu/miasta. Jeśli chcesz zbudować scraper cen Temu, musisz odpytywać z IP wdocelowym regionie. ProxyHat pozwala na geo-targetowanie na poziomie kraju i miasta, co jest niezbędne do wiarygodnego monitorowania cen.
Proxy datacenterowe w tym scenariuszu zawodzą nie tylko ze względu na blokady, ale też na zafałszowane dane: ceny mogą być wyższe lub produkty niedostępne, bo Temu rozpoznaje „nietypowy” ruch z farmy serwerów.
Konfiguracja ProxyHat — proxy rezydencyjne z geo i sesjami sticky
ProxyHat oferuje bramkę HTTP na gate.proxyhat.com:8080 i SOCKS5 na gate.proxyhat.com:1080. Geo-targetowanie i flagi sesji przekazujemy w nazwie użytkownika. Przykłady:
# USA, rotacja na żądanie
http://user-country-US:pass@gate.proxyhat.com:8080
# Niemcy, Berlin, sesja sticky
http://user-country-DE-city-berlin-session-abc123:pass@gate.proxyhat.com:8080
# SOCKS5
socks5://user-country-US-session-cart42:pass@gate.proxyhat.com:1080
Dla cart/shipping consistency używaj sesji sticky (-session-), aby wszystkie żądania dla jednego „koszyka” szły z tego samego IP. Do paginacji wyszukiwania rotuj IP na każde żądanie, aby rozproszyć obciążenie.
ProxyHat obsługuje proxy rezydencyjne, mobilne i datacenter. Do Temu rekomendujemy rezydencyjne z geo na poziomie miasta. Szczegóły i limity znajdziesz na stronie cennika.
Praktyczny przykład w Pythonie — pobranie strony produktu i parsowanie JSON
Poniższy przykład używa curl_cffi do emulacji fingerprintu Chrome oraz ProxyHat jako proxy HTTP. Kod pobiera stronę produktu, wyciąga blob __NEXT_DATA__ i drukuje skrócone podsumowanie.
import json
import re
from curl_cffi import requests
PROXY = "http://user-country-US:PASSWORD@gate.proxyhat.com:8080"
HEADERS = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/124.0.0.0 Safari/537.36",
"Accept-Language": "en-US,en;q=0.9",
}
def fetch_product(goods_id: str):
url = f"https://www.temu.com/goods-detail-{goods_id}.html"
r = requests.get(
url,
headers=HEADERS,
proxies={"http": PROXY, "https": PROXY},
impersonate="chrome124",
timeout=30,
)
r.raise_for_status()
return r.text
def extract_next_data(html: str) -> dict:
m = re.search(
r'<script id="__NEXT_DATA__" type="application/json">(.*?)</script>',
html,
re.DOTALL,
)
if not m:
raise ValueError("Nie znaleziono __NEXT_DATA__")
return json.loads(m.group(1))
def summarize(data: dict) -> dict:
store = data["props"]["pageProps"]["store"]
goods = store["goods"]
return {
"goods_id": goods.get("goods_id"),
"goods_name": goods.get("goods_name"),
"price": goods.get("salePrice", {}).get("amount"),
"sku_list": [
{"sku_id": s.get("sku_id"), "price": s.get("price")}
for s in goods.get("skuList", [])[:3]
],
}
if __name__ == "__main__":
html = fetch_product("301909891234")
data = extract_next_data(html)
print(json.dumps(summarize(data), indent=2, ensure_ascii=False))
Przykładowa (skrócona) odpowiedź JSON
{
"goods_id": "301909891234",
"goods_name": "Bezprzewodowe słuchawki Bluetooth",
"price": "12.99",
"sku_list": [
{"sku_id": "sku_001", "price": "12.99"},
{"sku_id": "sku_002", "price": "13.49"},
{"sku_id": "sku_003", "price": "14.99"}
]
}
Dla endpointu /api/poppy/v1/goods-detail struktura jest podobna, ale wymaga nagłówka anti_content. Bez niego otrzymasz {"success": false, "errorCode": "403"}. Token najlepiej pozyskać raz na sesję z renderowanej strony i podmieniać co kilka minut.
Paginacja, retry i sesje sticky
Do paginacji wyszukiwania używaj rotacji IP na każde żądanie (bez flagi -session-). Do operacji wymagających spójności stanu — np. sprawdzanie kosztów wysyłki dla konkretnego koszyka — używaj sesji sticky, aby wszystkie żądania szły z tego samego IP i widziały ten sam stan magazynowy.
import itertools
import time
from curl_cffi import requests
def search_page(keyword: str, page: int, proxy_user: str, proxy_pass: str):
# Rotacja IP: każde żądanie z nowym "seedem" w nazwie użytkownika
user = f"{proxy_user}-country-US-session-rot{page}"
proxy = f"http://{user}:{proxy_pass}@gate.proxyhat.com:8080"
url = "https://www.temu.com/api/poppy/v1/search"
params = {"keyword": keyword, "page": page, "limit": 50}
for attempt in range(3):
try:
r = requests.get(
url,
params=params,
proxies={"http": proxy, "https": proxy},
impersonate="chrome124",
timeout=30,
)
if r.status_code == 200:
return r.json()
time.sleep(2 ** attempt)
except Exception:
time.sleep(2 ** attempt)
return None
Rekomendowana strategia retry: 3 próby z wykładniczym backoffem (2s, 4s, 8s), limit współbieżności na poziomie 5–10 żądań na jeden proxy IP, oraz całkowity limit ~50 żądań na minutę na IP, aby utrzymać sukces powyżej 90%.
Typowe błędy i przypadki brzegowe
- Hashowane klasy CSS — nie buduj scraperów w oparciu o klasy typu
_2q1tC7w. Używaj atrybutówdata-uniqidi blobu JSON. - Brak
anti_content— endpointy JSON zwrócą 403 lub pusty wynik. Pozyskaj token z renderowanej strony. - Datacenter IP — natychmiastowa blokada lub zafałszowane ceny. Używaj proxy rezydencyjnych.
- Zmiana regionu w trakcie sesji — ceny mogą się skokowo zmienić. Utrzymuj jedno geo na sesję.
- Testy A/B — struktura DOM może się różnić między użytkownikami. Waliduj strukturę przed parsowaniem.
Etyka, ToS i aspekty prawne
Scrapowanie publicznego katalogu produktów i cen jest powszechnie stosowane do analizy konkurencji, ale musi być prowadzone z poszanowaniem warunków korzystania z serwisu Temu oraz obowiązującego prawa. Ogranicz się do danych publicznie dostępnych bez logowania. Nie scrapuj kont użytkowników, danych osobowych ani obszarów za autoryzacją.
W USA przypadki takie jak hiQ Labs vs LinkedIn wskazują, że scraping publicznie dostępnych danych nie narusza Computer Fraud and Abuse Act (CFAA), ale sytuacja prawna bywa złożona. W UE należy uwzględnić RODO, zwłaszcza jeśli przetwarzasz dane osobowe. Jeśli jesteś zarejestrowanym sprzedawcą na Temu, preferuj oficjalny merchant feed lub panel sprzedawcy zamiast scrapowania.
Praktyczne zasady:
- Respektuj
robots.txti progi rate-limit. - Nie obciążaj infrastruktury serwisu nadmiernym współbieżnym ruchem.
- Nie ponownie publikuj chronionych prawem autorskim obrazów bez licencji.
- Rozważ, czy potrzebujesz danych w czasie rzeczywistym, czy wystarczy dzienny snapshot.
Więcej o zastosowaniach scrapingowych znajdziesz w naszym przypadku użycia web scraping oraz śledzenia SERP.
Kiedy wolisz oficjalny merchant feed
Jeśli jesteś sprzedawcą na Temu, oficjalny panel sprzedawcy i API merchant feed są stabilniejsze i legalnie dostępne. Scrapowanie ma sens głównie dla analizy konkurencji i price intelligence, gdy nie masz bezpośredniego dostępu do danych konkurentów. Zawsze najpierw sprawdź, czy potrzebnych danych nie dostarcza oficjalny kanał.
Kluczowe wnioski
- Temu nie ma publicznego API — wybieraj między parsowaniem HTML a endpointami JSON z poprawnym
anti_content.- Cloudflare Turnstile + fingerprinting TLS sprawiają, że datacenter IP zawodzą — używaj proxy rezydencyjnych.
- Geo-targetowanie na poziomie kraju/miasta jest obowiązkowe, bo ceny i wysyłka różnią się regionalnie.
- Sesje sticky (
-session-) zapewniają spójność koszyka/wysyłki; rotacja IP — paginację wyszukiwania.- Ogranicz się do publicznego katalogu, respektuj ToS i RODO.
Gotowy do zbudowania własnego API danych produktów Temu? Skonfiguruj proxy rezydencyjne ProxyHat z geo na poziomie miasta i zacznij od małej partii żądań. Dokumentację techniczną znajdziesz na docs.proxyhat.com.






