Парсинг данных Temu в 2026: выбор между HTML и внутренним JSON API
Temu — один из самых быстрорастущих e-commerce маркетплейсов, и потребность в парсинге данных Temu растёт вместе с ним. Команды ценовой разведки, конкурентной аналитики и сборщики данных для AI-обучения регулярно обращаются к каталогу Temu, но быстро сталкиваются с жёсткой антибот-инфраструктурой. У Temu нет публичного API для каталога, поэтому приходится выбирать между двумя подходами: парсингом нестабильного HTML карточек товаров и обращением к внутренним JSON-эндпоинтам вроде /api/poppy/v1/search и /api/poppy/v1/goods-detail.
HTML-подход кажется проще — загружаешь страницу, ищешь селекторы, достаёшь цену и название. Но классы Temu хэшированы и меняются при каждом деплое, а вёрстка карточек перестраивается еженедельно. JSON-эндпоинты стабильнее по структуре, но требуют корректного заголовка anti_content — подписанного токена, который генерируется клиентским JavaScript и привязан к сессии браузера. Без него сервер возвращает 403 или пустой результат.
В этом руководстве мы разберём оба пути, покажем рабочий Python-пример с curl_cffi и прокси ProxyHat, и объясним, почему резидентные прокси с гео-таргетингом по городам — не опция, а необходимость для парсера цен Temu.
Технический контекст: почему Temu сложно скрейпить
Temu работает на инфраструктуре PDD Holdings и использует многоуровневую защиту от автоматизированного доступа. Вот основные компоненты:
- Cloudflare Turnstile — капча-виджет, который проверяет поведение мыши, отпечаток браузера и репутацию IP. По данным официальной документации Cloudflare, Turnstile анализирует более 30 сигналов, включая TLS-фингерпринт и HTTP/2 кадры.
- Подписанный заголовок anti_content — JWT-подобный токен, генерируемый клиентским кодом. Он кодирует временную метку, идентификатор сессии и контрольную сумму параметров запроса. Сервер валидирует его при каждом обращении к JSON-эндпоинтам.
- TLS/HTTP2 фингерпринтинг — Temu отличает реальные браузеры от скрейперов по JA3/JA4 хэшу и настройкам ALPN. Датацентр-IP с Python-запросом отбрасывается за 1–2 запроса.
- Динамическая гео-ценовая логика — цены, скидки и стоимость доставки зависят от региона пользователя. Один и тот же товар может стоить $4.98 в США и €6.20 в Германии.
Это означает, что обычный requests.get() с датацентр-прокси не работает. Нужен браузерный фингерпринт, корректный anti_content и резидентный IP из нужной страны.
Антибот-стек Temu: что именно блокирует
Рассмотрим подробнее, как каждый слой защиты влияет на скрейпинг:
| Слой защиты | Что проверяет | Обход |
|---|---|---|
| Cloudflare Turnstile | Поведение, canvas-отпечаток, репутация IP | Резидентные прокси + браузерный движок (Playwright/curl_cffi) |
| anti_content токен | Подпись параметров запроса и timestamp | Реверс-инжиниринг JS или рендеринг страницы в браузере |
| TLS/JA3 фингерпринт | Набор шифров, расширения TLS, порядок заголовков | curl_cffi с профилем Chrome или httpx с tls-impersonate |
| Rate limiting | Количество запросов с одного IP/сессии | Ротация резидентных IP, задержки 2–5 секунд |
Где искать данные: встроенный state и JSON-эндпоинты
Тем, кто строит API данных товаров Temu для внутреннего использования, важно понимать, где живут данные. Есть два основных источника:
1. Встроенный __NEXT_DATA__ / state blob
Страницы Temu (как поисковые результаты, так и карточки товаров) содержат встроенный JSON-блоб состояния приложения. Он встраивается в <script id="__NEXT_DATA__" type="application/json"> или в инлайн-скрипт с переменной вроде window.__INITIAL_STATE__. Этот блоб содержит структурированные данные о товарах, ценах, SKU и отзывах — без необходимости парсить HTML-карточки.
Пример XPath для извлечения:
//script[@id="__NEXT_DATA__"]/text()
После парсинга JSON вы получаете объект с полями вроде goods_id, salePrice, skuList, goodsName. Это надёжнее, чем CSS-селекторы по хэшированным классам вроде .r-store- goods-title_113e, которые меняются при каждом релизе.
2. Внутренние JSON-эндпоинты
За сеткой товаров на странице поиска стоят запросы к:
POST https://www.temu.com/api/poppy/v1/search
POST https://www.temu.com/api/poppy/v1/goods-detail
Эти эндпоинты возвращают чистый JSON с полным набором данных: цены, варианты SKU, изображения, рейтинги. Но они требуют:
- Корректного
anti_contentзаголовка — подписанного токена. - Browser-like
User-Agentи набора заголовков (Referer,Origin,Sec-Ch-Ua). - Куки-сессии, установленной при первичной загрузке страницы.
- Резидентного IP — датацентр-IP получает
403почти мгновенно.
Атрибут data-uniqid на карточках товаров содержит идентификатор, который можно использовать как goods_id для последующего запроса к goods-detail.
Rate-limit пороги и почему резидентные прокси обязательны
Temu применяет агрессивный rate-limiting. Эмпирические наблюдения показывают следующие пороги:
- ~50 запросов с одного датацентр-IP за 60 секунд → 403 или пустой ответ.
- ~150–200 запросов с одного резидентного IP за час → мягкая блокировка (CAPTCHA challenge).
- ~500 запросов с одной сессии (куки + IP) → жёсткая блокировка на 24 часа.
Кроме того, цены и стоимость доставки варьируются по регионам. Товар, показанный с IP в Орегоне, может иметь бесплатную доставку, а тот же товар с IP в Нью-Йорке — платную. Это означает, что для корректного парсера цен Temu нужно использовать резидентные прокси с гео-таргетингом на уровне страны, а иногда и города.
ProxyHat позволяет указать страну и город прямо в имени пользователя:
http://user-country-US-city-newyork:pass@gate.proxyhat.com:8080
Это даёт IP из нужного региона, что критически важно для ценовой разведки. Подробнее о доступных локациях — на странице локаций ProxyHat.
Рабочий пример: Python + curl_cffi + ProxyHat
Для обхода TLS-фингерпринтинга используем curl_cffi — библиотеку, которая имитирует TLS-отпечаток Chrome. Для проксирования трафика через резидентные IP ProxyHat настроим HTTP-прокси на gate.proxyhat.com:8080.
Установка зависимостей
pip install curl_cffi beautifulsoup4 lxml
Скрейпинг страницы товара через HTML + __NEXT_DATA__
from curl_cffi import requests
import json
from bs4 import BeautifulSoup
PROXY = "http://user-country-US-city-newyork:pass@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": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
"Sec-Ch-Ua": '"Chromium";v="124", "Google Chrome";v="124"',
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "none",
}
def fetch_product_page(goods_id: str, session_id: str = "temu-sess-1"):
url = f"https://www.temu.com/goods/{goods_id}.html"
proxies = {"http": PROXY, "https": PROXY}
# impersonate="chrome124" включает TLS/JA3 профиль Chrome
response = requests.get(
url,
headers=HEADERS,
proxies=proxies,
impersonate="chrome124",
timeout=30,
)
if response.status_code != 200:
print(f"Ошибка {response.status_code} для goods_id={goods_id}")
return None
soup = BeautifulSoup(response.text, "lxml")
next_data_script = soup.find("script", id="__NEXT_DATA__")
if not next_data_script:
# Альтернативный путь: window.__INITIAL_STATE__
for script in soup.find_all("script"):
if script.string and "__INITIAL_STATE__" in (script.string or ""):
start = script.string.find("=") + 2
raw = script.string[start:]
return json.loads(raw.rstrip(";"))
return None
return json.loads(next_data_script.string)
# Пример вызова
data = fetch_product_page("502099876543")
if data:
goods = data.get("props", {}).get("pageProps", {}).get("goods", {})
print(json.dumps({
"goods_id": goods.get("goodsId"),
"goods_name": goods.get("goodsName"),
"sale_price": goods.get("salePrice"),
"original_price": goods.get("marketPrice"),
"sku_count": len(goods.get("skuList", [])),
}, indent=2))
Пример усечённого JSON-ответа
{
"goods_id": "502099876543",
"goods_name": "Wireless Bluetooth Earbuds, 2026 Model",
"sale_price": {"amount": 4.98, "currency": "USD"},
"market_price": {"amount": 12.99, "currency": "USD"},
"sku_list": [
{"sku_id": "sku_001", "spec": "Black", "price": 4.98, "stock": 3421},
{"sku_id": "sku_002", "spec": "White", "price": 4.98, "stock": 1875},
{"sku_id": "sku_003", "spec": "Blue", "price": 5.49, "stock": 920}
],
"shipping": {"free_threshold": 5.90, "estimated_days": "3-5"},
"rating": 4.6,
"review_count": 12847
}
Скрейпинг через внутренний JSON-эндпоинт (goods-detail)
from curl_cffi import requests
import json
PROXY = "http://user-country-US-session-cart01:pass@gate.proxyhat.com:8080"
DETAIL_URL = "https://www.temu.com/api/poppy/v1/goods-detail"
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",
"Content-Type": "application/json",
"Origin": "https://www.temu.com",
"Referer": "https://www.temu.com/",
"Accept": "application/json, text/plain, */*",
"Sec-Ch-Ua": '"Chromium";v="124", "Google Chrome";v="124"',
}
def fetch_goods_detail(goods_id: str, anti_content: str, session_id: str):
payload = {
"goodsId": goods_id,
"antiContent": anti_content,
"sessionId": session_id,
}
response = requests.post(
DETAIL_URL,
json=payload,
headers=HEADERS,
proxies={"http": PROXY, "https": PROXY},
impersonate="chrome124",
timeout=30,
)
if response.status_code == 200:
return response.json()
else:
print(f"Ошибка {response.status_code}: {response.text[:200]}")
return None
Главная сложность здесь — получение валидного anti_content. На практике большинство команд используют гибридный подход: загружают страницу товара в headless-браендере (Playwright), извлекают anti_content из перехваченного запроса, а затем делают серию быстрых JSON-запросов через curl_cffi с прокси.
Sticky-сессии, ретраи и пагинация
Sticky-сессии для консистентности корзины
При сборе данных о доставке и налогах важно, чтобы серия запросов шла с одного IP. ProxyHat поддерживает sticky-сессии через флаг -session- в имени пользователя:
http://user-country-US-session-cart-abc123:pass@gate.proxyhat.com:8080
Это гарантирует, что все запросы в рамках сессии cart-abc123 пойдут через один и тот же резидентный IP. Для пагинации по результатам поиска используйте один и тот же session-ID, чтобы Temu воспринимала запросы как одну пользовательскую сессию.
Стратегия ретраев
Даже с резидентными прокси часть запросов будет отклонена. Рекомендуемая стратегия:
- Экспоненциальная задержка — 1с, 2с, 4с, 8с между ретраями.
- Максимум 3 ретрая на один запрос, затем смена IP.
- Смена session-ID при получении 403 — это сбрасывает связь с заблокированной сессией.
- Случайный джиттер 0.5–2.5 секунды между запросами для имитации человеческого поведения.
import time
import random
from curl_cffi import requests
PROXY_TEMPLATE = (
"http://user-country-US-session-{sess}:pass@gate.proxyhat.com:8080"
)
def fetch_with_retry(url, max_retries=3):
for attempt in range(max_retries):
session_id = f"temu-{random.randint(1000, 999999)}"
proxy = PROXY_TEMPLATE.format(sess=session_id)
try:
resp = requests.get(
url,
proxies={"http": proxy, "https": proxy},
impersonate="chrome124",
timeout=30,
)
if resp.status_code == 200:
return resp
elif resp.status_code == 403:
print(f"403 на попытке {attempt + 1}, смена сессии")
time.sleep(2 ** attempt + random.uniform(0.5, 2.5))
continue
except Exception as e:
print(f"Исключение: {e}")
time.sleep(2 ** attempt)
return None
Пагинация
Temu использует курсорную пагинацию в JSON-эндпоинтах. Ответ содержит поле nextCursor или pageId, который нужно передать в следующем запросе. Обычно глубина ограничена ~50 страницами (~1000 товаров) на один поисковый запрос.
Этика, TOS и правовые оговорки
Скрейпинг публичных данных каталога Temu — товаров, цен, отзывов — находится в серой зоне. Вот ключевые принципы:
- Только публичные данные — не скрейпите данные аккаунтов, личные сообщения, заказы или внутренние страницы продавцов, требующие авторизации.
- Соблюдайте robots.txt — Temu частично запрещает скрейпинг через robots.txt. Проверьте
https://www.temu.com/robots.txtперед началом. - CFAA и GDPR — в США закон Computer Fraud and Abuse Act может применяться к несанкционированному доступу. В ЕС GDPR регулирует сбор персональных данных (например, отзывов с именами пользователей).
- Скорость и нагрузка — не отправляйте более 1 запроса в секунду на один IP. Используйте задержки и уважайте ресурсы сервера.
- Официальный merchant feed — если вы партнёр Temu или продавец, у вас может быть доступ к официальному API продавца через Temu Seller Center. Это всегда предпочтительнее скрейпинга.
Скрейпинг публичных каталогов для ценовой аналитики — распространённая практика, но всегда проверяйте TOS платформы и консультируйтесь с юристом при коммерческом использовании данных.
Настройка ProxyHat: пошаговая инструкция
Для начала сбора данных через ProxyHat:
- Зарегистрируйтесь на dashboard.proxyhat.com и выберите тариф резидентных прокси. Подробнее — на странице цен ProxyHat.
- Получите учётные данные (username и password) из дашборда.
- Настройте гео-таргетинг через имя пользователя:
user-country-US-city-losangeles. - Используйте sticky-сессии для серий запросов:
user-country-DE-session-batch01. - Для SOCKS5 подключений используйте порт 1080:
socks5://user-country-US:pass@gate.proxyhat.com:1080.
Полная документация по параметрам доступна на docs.proxyhat.com. Больше примеров использования прокси для веб-скрейпинга — в разделе use-case веб-скрейпинга и SERP-трекинга.
Ключевые выводы
- JSON-эндпоинты стабильнее HTML, но требуют валидного
anti_contentтокена — используйте гибридный подход с headless-браузером для первичной загрузки. - TLS-фингерпринтинг — главный барьер:
curl_cffiсimpersonate="chrome124"решает эту проблему. - Резидентные прокси обязательны — датацентр-IP блокируется за 1–2 запроса. Гео-таргетинг по странам и городам критичен для корректности цен.
- Sticky-сессии через
-session-обеспечивают консистентность при пагинации и сборе данных о доставке. - Соблюдайте TOS и правовые нормы — только публичные данные, разумные задержки, и предпочтение официальному API при наличии доступа.
- Rate-limit пороги: ~50 запросов/мин на IP, ~150–200/час — используйте ротацию IP и задержки 2–5 секунд.
Часто задаваемые вопросы
Можно ли скрейпить Temu без прокси?
Технически да, но практически — нет. Temu блокирует датацентр-IP за 1–2 запроса через Cloudflare Turnstile и TLS-фингерпринтинг. Без резидентных прокси вы получите 403 или CAPTCHA-челлендж почти мгновенно. Для серийного сбора данных резидентные прокси с гео-таргетингом — обязательное условие.
Какой тип прокси лучше для парсинга Temu?
Резидентные прокси — оптимальный выбор. Они используют IP реальных устройств в ISP-сетях, что делает их неотличимыми от обычных пользователей. Мобильные прокси тоже работают, но стоят дороже. Датацентр-прокси не подходят — Temu блокирует их на уровне Cloudflare. Гео-таргетинг по странам и городам важен, так как цены и доставка варьируются по регионам.
Как избежать блокировок при скрейпинге Temu?
Используйте резидентные прокси с ротацией IP, имитируйте TLS-отпечаток браузера через curl_cffi, добавляйте случайные задержки 2–5 секунд между запросами, меняйте session-ID при получении 403, и не превышайте 50 запросов в минуту с одного IP. Sticky-сессии помогают при пагинации, но периодическая смена сессии снижает риск блокировки.
Есть ли официальный API Temu для товаров и цен?
Публичного API каталога Temu не существует. Продавцы имеют доступ к Seller Center API для управления своими товарами, но он не предоставляет доступ к чужому каталогу. Для ценовой разведки единственные варианты — скрейпинг публичных страниц или партнёрские соглашения с Temu. Всегда проверяйте TOS перед началом сбора данных.






