Scraper Temu en 2026 : le dilemme HTML vs endpoints JSON internes
Si vous cherchez à scraper les données produits et prix Temu en 2026, vous vous heurtez immédiatement à un choix architectural fondamental. Temu n'expose aucune API publique pour son catalogue grand public. Vous devez donc décider entre deux approches : parser le HTML rendu (cartes produits volatiles, classes CSS hachées) ou cibler directement les endpoints JSON internes que le frontend appelle pour peupler la grille de résultats.
La première approche — scraping HTML — consiste à charger une page de recherche ou de produit, attendre le rendu côté client, puis extraire les données depuis le DOM. C'est fragile : les classes CSS de Temu sont hachées (ex. _2a8b1f3), changent à chaque déploiement, et la grille est hydratée dynamiquement par JavaScript. Vous risquez de rater des produits si le rendu est incomplet.
La seconde approche — endpoints JSON internes — est nettement plus robuste. Temu utilise un backend API préfixé /api/poppy/v1/ qui renvoie du JSON structuré pour les recherches (/search) et les détails produit (/goods-detail ou variantes). Ces endpoints alimentent le frontend Next.js et contiennent des champs riches : goods_id, goods_name, salePrice, skuList, imageList, etc. Le compromis : ces endpoints nécessitent des en-têtes signés (notamment anti_content) et un fingerprint TLS cohérent, sinon vous recevez un 403 ou un challenge Cloudflare.
Règle de base : si vous avez besoin de volume et de fiabilité, visez les endpoints JSON. Si vous scrapez occasionnellement une poignée de pages, le HTML peut suffire, mais prévoyez une maintenance régulière des sélecteurs.
Le contexte technique : pourquoi Temu est difficile à scraper
Temu est exploité par PDD Holdings, la même maison mère que Pinduoduo, et hérite d'une infrastructure anti-bot mature. Trois couches de protection rendent le scraping non trivial :
1. Cloudflare Turnstile et challenge JavaScript
Temu est protégé par Cloudflare Turnstile ainsi que par les règles WAF de Cloudflare. Les requêtes suspectes (IP datacenter, fingerprint TLS anormal, absence d'en-têtes navigateur) déclenchent un challenge JavaScript interstitiel. Si vous utilisez requests ou httpx standard, vous obtiendrez souvent un HTTP 403 avec une page challenge au lieu du contenu attendu.
2. L'en-tête signé anti_content
Les endpoints /api/poppy/v1/ exigent un en-tête anti_content (parfois passé en paramètre de body) qui contient un token signé généré côté client par du code JavaScript obfusqué. Ce token encode des informations sur le navigateur, le timestamp, et potentiellement un nonce. Sans ce token valide, l'API renvoie une erreur errno": 403 ou "errno": 10001. Reproduire ce token nécessite soit d'exécuter le JS via un navigateur headless (Playwright/Puppeteer), soit de rétro-ingénierier l'algorithme — ce qui est fragile et juridiquement risqué.
3. TLS / HTTP2 fingerprinting
Cloudflare et Temu utilisent le fingerprinting TLS (JA3/JA4) et l'empreinte HTTP/2 pour distinguer les vrais navigateurs des bibliothèques HTTP. requests de Python produit une empreinte JA3 reconnaissable instantanément. Les IP datacenter sont également flaggées : Cloudflare maintient une liste de plages d'IP hébergées (AWS, GCP, OVH, Hetzner) et applique un niveau de challenge plus élevé à ces plages.
C'est pourquoi les proxies résidentiels sont indispensables : une IP résidentielle US passera le filtre géographique et le filtre de réputation, tandis qu'une IP datacenter sera challenged dans la majorité des cas.
Localiser les données : __NEXT_DATA__, endpoints JSON et attributs data-uniqid
Que vous choisissiez le HTML ou l'API, vous devez savoir où se trouvent les données. Voici les trois sources principales :
L'objet __NEXT_DATA__ embarqué
Temu utilise Next.js pour son frontend. Chaque page produit ou de recherche contient une balise <script id="__NEXT_DATA__" type="application/json"> avec un blob JSON massif représentant l'état initial hydraté. Ce blob contient les données produit avant même que JavaScript ne s'exécute. Vous pouvez le parser directement :
import json, re
from parsel import Selector
html = response.text
sel = Selector(html)
next_data_raw = sel.css('script#__NEXT_DATA__::text').get()
next_data = json.loads(next_data_raw)
# Les données produit sont imbriquées profondément
# Le chemin exact varie — cherchez goods_id ou goodsList
props = next_data.get('props', {}).get('pageProps', {})
goods_list = props.get('goodsList', [])
for g in goods_list[:3]:
print(g.get('goods_id'), g.get('goods_name'), g.get('salePrice'))
Cette méthode évite d'avoir à reproduire le token anti_content pour la page initiale, car le serveur Next.js injecte les données lors du rendu côté serveur (SSR). C'est le point d'entrée le plus fiable pour une page produit unique.
Les endpoints JSON derrière la grille
Pour la pagination et la recherche programmatique, le frontend appelle des endpoints comme :
GET /api/poppy/v1/search?keyword=...&page=...&pageSize=...— résultats de recherchePOST /api/poppy/v1/goods/detail— détails produit complets (body JSON avecgoods_id)
Ces endpoints renvoient du JSON propre mais nécessitent les en-têtes signés. Si vous utilisez un navigateur headless pour générer le anti_content, vous pouvez intercepter ces appels et les rejouer.
Classes CSS hachées et data-uniqid
Si vous tombez sur le parsing HTML pur, les cartes produits utilisent des classes CSS hachées qui changent à chaque build. Cherchez plutôt les attributs stables :
data-uniqid="..."— identifiant unique de carte produitdata-goods-id="..."— ID produit (plus fiable que les classes CSS)- Sélecteur XPath :
//div[@data-goods-id]pour capturer toutes les cartes
# Exemple XPath robuste pour les cartes produit
cards = sel.xpath('//div[@data-goods-id]')
for card in cards:
goods_id = card.xpath('@data-goods-id').get()
price = card.xpath('.//span[contains(@class,"price")]/text()').get()
title = card.xpath('.//span[contains(@class,"title")]/text()').get()
Seuils de rate-limit et pourquoi les proxies résidentiels avec géo ville sont obligatoires
Temu n'a pas de seuil de rate-limit documenté, mais les observations empiriques montrent que :
- Une même IP peut effectuer environ 50–80 requêtes sur les pages HTML avant de recevoir un challenge Cloudflare.
- Les endpoints
/api/poppy/v1/sont plus stricts : 20–30 requêtes par IP et par fenêtre de 10 minutes environ avant un 403. - Les IP datacenter sont challenged quasi immédiatement (dès 1–5 requêtes).
Plus important encore : les prix et les options de livraison varient par région. Un produit à 2,48 $ aux États-Unis peut s'afficher à 3,12 € en France ou ne pas être disponible en Allemagne. Les frais de livraison, les délais et la disponibilité du stock sont géo-dépendants. Si vous faites du price monitoring international, vous devez simuler des utilisateurs dans chaque marché cible.
Avec ProxyHat, vous pouvez spécifier le pays et la ville directement dans le nom d'utilisateur :
# Proxy résidentiel US (New York)
http://user-country-US-city-newyork:pass@gate.proxyhat.com:8080
# Proxy résidentiel DE (Berlin)
http://user-country-DE-city-berlin:pass@gate.proxyhat.com:8080
# Proxy résidentiel FR (Paris)
http://user-country-FR-city-paris:pass@gate.proxyhat.com:8080
Cela garantit que les prix récupérés correspondent à ce qu'un utilisateur réel dans cette région verrait. Consultez notre page des localisations pour la liste complète des pays et villes disponibles.
Exemple Python complet : curl_cffi + ProxyHat pour scraper une page produit Temu
Pour contourner le fingerprinting TLS, nous utilisons curl_cffi, une bibliothèque Python qui s'appuie sur libcurl avec impersonation de navigateur (JA3/JA4 et HTTP/2). Combinée aux proxies résidentiels ProxyHat, elle offre le meilleur ratio fiabilité/coût.
from curl_cffi import requests as cffi_requests
import json, re
from parsel import Selector
# Configuration ProxyHat — proxy résidentiel US
PROXY_URL = "http://user-country-US-city-newyork:pass@gate.proxyhat.com:8080"
TARGET_URL = "https://www.temu.com/goods.html?goods_id=301909513"
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": "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",
"Referer": "https://www.temu.com/",
}
session = cffi_requests.Session(impersonate="chrome124")
response = session.get(
TARGET_URL,
headers=HEADERS,
proxies={"http": PROXY_URL, "https": PROXY_URL},
timeout=30,
)
print(f"Status: {response.status_code}")
if response.status_code == 200:
sel = Selector(response.text)
next_data_raw = sel.css('script#__NEXT_DATA__::text').get()
if next_data_raw:
data = json.loads(next_data_raw)
# Navigation dans la structure — chemin à adapter
store = data.get("props", {}).get("pageProps", {})
goods = store.get("goods", store.get("goodsDetail", {}))
print(json.dumps({
"goods_id": goods.get("goodsId", goods.get("goods_id")),
"goods_name": goods.get("goodsName", goods.get("goods_name")),
"sale_price": goods.get("salePrice", goods.get("minNormalPrice")),
"sku_list_count": len(goods.get("skuList", [])),
}, indent=2, ensure_ascii=False))
else:
print("__NEXT_DATA__ introuvable — possible challenge Cloudflare")
else:
print(f"Bloqué — status {response.status_code}")
Exemple de réponse JSON tronquée
Voici un aperçu de ce que vous obtenez en parsant __NEXT_DATA__ pour une page produit :
{
"goods_id": "301909513",
"goods_name": "Mini Projecteur Portable LED 1080P",
"sale_price": {
"amount": 12.98,
"currency": "USD",
"symbol": "$"
},
"min_normal_price": {
"amount": 19.99,
"currency": "USD"
},
"sku_list": [
{
"sku_id": "sku_88421",
"sku_name": "Blanc",
"price": { "amount": 12.98, "currency": "USD" },
"stock": 3421
},
{
"sku_id": "sku_88422",
"sku_name": "Noir",
"price": { "amount": 13.49, "currency": "USD" },
"stock": 1893
}
],
"image_list": [
"https://img.kwcdn.com/product/301909513/1.jpg",
"https://img.kwcdn.com/product/301909513/2.jpg"
],
"shipping_info": {
"estimated_days": "5-8",
"free_shipping": true
}
}
Notez que les noms exacts des champs peuvent varier selon la version du frontend. Utilisez json.dumps() avec indent=2 pour inspecter la structure complète lors de vos premiers tests.
Sessions sticky, retries et pagination
Sessions sticky pour la cohérence panier/livraison
Si vous scrapez des données qui impliquent un flux multi-étapes (ajout au panier, calcul de livraison, checkout simulé), vous devez maintenir la même IP de sortie sur plusieurs requêtes. ProxyHat supporte les sessions sticky via le flag -session- dans le nom d'utilisateur :
# Session sticky — même IP pour toutes les requêtes
http://user-country-US-session-temu001:pass@gate.proxyhat.com:8080
# Session sticky avec ville
http://user-country-US-city-chicago-session-temu002:pass@gate.proxyhat.com:8080
L'identifiant de session (temu001) peut être n'importe quelle chaîne alphanumérique. Tant que vous utilisez le même identifiant, ProxyHat route vos requêtes via la même IP résidentielle. Les sessions expirent après une période d'inactivité (généralement 10–15 minutes), donc relancez une session si vous observez un changement d'IP en milieu de flux.
Stratégie de retries
Voici un pattern de retry robuste pour gérer les 403 et 429 :
import time, random
def fetch_with_retry(url, max_retries=3):
for attempt in range(max_retries):
try:
resp = session.get(url, headers=HEADERS,
proxies={"http": PROXY_URL, "https": PROXY_URL},
timeout=30)
if resp.status_code == 200:
return resp
elif resp.status_code in (403, 429):
# Challenge ou rate-limit — backoff exponentiel + jitter
wait = (2 ** attempt) + random.uniform(0.5, 2.0)
print(f"Tentative {attempt+1}: {resp.status_code}, attente {wait:.1f}s")
time.sleep(wait)
else:
print(f"Erreur HTTP {resp.status_code}")
return None
except Exception as e:
print(f"Exception: {e}")
time.sleep(2 ** attempt)
return None
Pagination
Temu pagine ses résultats de recherche via un paramètre page (ou offset sur l'API). Pour éviter de déclencher des challenges :
- Limitez à 3–5 pages par session IP avant de faire tourner l'IP.
- Ajoutez un délai aléatoire de 2–5 secondes entre les pages.
- Faites tourner le flag
-session-pour changer d'IP tous les quelques pages. - Ne dépassez pas 100 requêtes concurrentes par compte proxy pour éviter la détection de pattern.
ProxyHat : configuration et liens utiles
Pour résumer la configuration ProxyHat dans le contexte Temu :
| Paramètre | Valeur | Usage |
|---|---|---|
| Gateway HTTP | gate.proxyhat.com:8080 | Proxy HTTP standard |
| Gateway SOCKS5 | gate.proxyhat.com:1080 | SOCKS5 (utile si HTTP est filtré) |
| Géo pays | user-country-US:pass | Simule un utilisateur US |
| Géo ville | user-country-US-city-newyork:pass | Précision ville pour prix locaux |
| Session sticky | user-session-abc123:pass | IP fixe pour flux multi-requêtes |
| Combo complet | user-country-US-city-newyork-session-t1:pass | Géo + sticky |
Pour les détails de tarification et les plans adaptés au scraping à grande échelle, consultez notre page de tarification. Pour des cas d'usage liés au scraping web et au suivi SERP, voir scraping web et suivi SERP. La documentation technique complète est disponible sur docs.proxyhat.com.
Éthique, conditions d'utilisation et limites légales
Le scraping de Temu soulève des questions légales qu'il faut aborder sérieusement :
- Données publiques uniquement : ce guide couvre l'extraction du catalogue public visible sans connexion. Ne scrapez pas de données derrière un compte (historique de commandes, données personnelles, API marchand).
- CFAA (US) et équivalents européens : aux États-Unis, le Computer Fraud and Abuse Act (18 U.S.C. § 1030) peut s'appliquer si l'accès dépasse les autorisations accordées. En Europe, le RGPD s'applique aux données personnelles — mais les prix produits ne sont pas des données personnelles.
- Respect du
robots.txt: vérifiez toujourshttps://www.temu.com/robots.txtavant de scraper. Si des chemins sont exclus, ne les scrapez pas. - Limitation de débit raisonnable : n'envoyez pas des milliers de requêtes par seconde. Un rythme respectueux (1–2 req/s par IP) réduit la charge sur l'infrastructure cible et le risque de bannissement.
- API marchand officielle : si vous êtes un vendeur ou partenaire Temu, préférez l'API Merchant Feed officielle pour accéder à vos propres données produit. C'est plus fiable, légal, et ne nécessite pas de proxies.
Le scraping de données publiques à des fins de price intelligence est généralement toléré tant que vous respectez les ToS, le rythme raisonnable, et que vous n'inférez pas de données personnelles. Consultez un avocat si votre cas d'usage est commercial à grande échelle.
Points clés à retenir
- Préférez les endpoints JSON internes (
/api/poppy/v1/) ou le blob__NEXT_DATA__au parsing HTML — plus stable et plus riche. - Le fingerprinting TLS est le premier filtre : utilisez
curl_cffiavecimpersonate="chrome124"pour passer les checks JA3/JA4. - Les proxies résidentiels avec géo ville sont obligatoires : les prix et la disponibilité varient par région. Utilisez
-country-US-city-newyorkpour simuler un utilisateur local. - Limitez à 20–30 requêtes par IP sur les endpoints API, et 50–80 sur le HTML, avant de faire tourner l'IP.
- Utilisez les sessions sticky (
-session-) pour les flux multi-étapes (panier, livraison). - Respectez les ToS et le
robots.txt— scrapez uniquement le catalogue public, pas les données de compte.
FAQ
Qu'est-ce que le scraping de données produits et prix Temu en 2026 ?
C'est l'extraction automatisée des informations du catalogue public de Temu (prix, nom, SKU, images, disponibilité) en 2026, dans un contexte où la plateforme a renforcé ses défenses anti-bot (Cloudflare Turnstile, fingerprinting TLS, token anti_content signé). L'absence d'API publique force les data engineers à soit parser le HTML rendu, soit cibler les endpoints JSON internes comme /api/poppy/v1/search et /api/poppy/v1/goods/detail, en s'appuyant sur des proxies résidentiels pour contourner les blocages géo et de réputation IP.
Pourquoi le scraping Temu matters-t-il pour les utilisateurs de proxies ?
Temu est l'un des rares marketplaces où les prix varient significativement par région géographique, ce qui rend le geo-targeting au niveau ville essentiel pour le price monitoring. De plus, l'infrastructure anti-bot de Temu (héritée de PDD Holdings) flagg instantanément les IP datacenter. Les proxies résidentiux avec géo ciblée ne sont pas une option — ils sont la condition sine qua non pour obtenir des données fiables et représentatives du marché réel.
Quel type de proxy fonctionne le mieux pour scraper Temu ?
Les proxies résidentiels avec géo-targeting au niveau pays et ville sont les plus efficaces. Les proxies datacenter sont challenged quasi immédiatement par Cloudflare. Les proxies mobiles fonctionnent aussi mais sont plus coûteux et plus lents. Pour Temu, un proxy résidentiel US (ex. user-country-US-city-newyork:pass@gate.proxyhat.com:8080) offre le meilleur équilibre entre fiabilité, vitesse et coût. Utilisez les sessions sticky pour les flux multi-requêtes.
Comment éviter les blocages quand on scrape Temu ?
Combinez quatre leviers : (1) utilisez curl_cffi avec impersonation Chrome pour matcher le fingerprint TLS/HTTP2 d'un vrai navigateur ; (2) routez via des proxies résidentiels avec géo ville pour éviter le flag datacenter ; (3) limitez à 20–30 requêtes par IP sur l'API et 50–80 sur le HTML avant de faire tourner l'IP ; (4) ajoutez des délais aléatoires de 2–5 secondes entre les requêtes et un backoff exponentiel sur les 403/429. Évitez les patterns réguliers qui révèlent un bot.
Peut-on utiliser l'API marchand officielle de Temu au lieu de scraper ?
Oui, si vous êtes vendeur ou partenaire Temu, l'API Merchant Feed officielle donne accès à vos propres données produit de manière fiable et légale. Cependant, elle ne couvre pas le catalogue complet des autres vendeurs — pour le price monitoring concurrentiel, le scraping reste la seule option. Dans tous les cas, scrapez uniquement les données publiques visibles sans connexion, respectez le robots.txt, et consultez un avocat pour les cas d'usage commerciaux à grande échelle.






