Как скрейпить данные товаров и цен Temu в 2026: прокси, антибот и скрытый JSON

Практическое руководство по парсингу Temu: внутренние JSON-эндпоинты, обход Cloudflare Turnstile, TLS-фингерпринтинг и настройка резидентных прокси ProxyHat для стабильного сбора данных.

How to Scrape Temu Product and Price Data in 2026: Proxies, Anti-Bot, and the Hidden JSON

Парсинг данных 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. Экспоненциальная задержка — 1с, 2с, 4с, 8с между ретраями.
  2. Максимум 3 ретрая на один запрос, затем смена IP.
  3. Смена session-ID при получении 403 — это сбрасывает связь с заблокированной сессией.
  4. Случайный джиттер 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:

  1. Зарегистрируйтесь на dashboard.proxyhat.com и выберите тариф резидентных прокси. Подробнее — на странице цен ProxyHat.
  2. Получите учётные данные (username и password) из дашборда.
  3. Настройте гео-таргетинг через имя пользователя: user-country-US-city-losangeles.
  4. Используйте sticky-сессии для серий запросов: user-country-DE-session-batch01.
  5. Для 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 перед началом сбора данных.

Готовы начать?

Доступ к более чем 50 млн резидентных IP в 148+ странах с AI-фильтрацией.

Смотреть ценыРезидентные прокси
← Вернуться в Блог