2026년 Temu 상품 및 가격 데이터 스크래핑 완전 가이드: 프록시, 안티봇, 숨겨진 JSON

Temu에는 공개 API가 없어 HTML 파싱과 내부 JSON 엔드포인트 중 선택해야 합니다. 이 가이드는 Cloudflare Turnstile, 서명된 anti_content 토큰, TLS 지문을 우회하고 residential 프록시로 안정적으로 Temu 상품 및 가격 데이터를 수집하는 방법을 설명합니다.

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

Temu는 2023년 미국에서 가장 다운로드된 앱이 되었고, 2024년에는 글로벌 활성 사용자가 4억 명을 넘었습니다. 이 압도적인 카탈로그와 변동성 큰 가격 구조는 가격 인텔리전스 팀과 이커머스 데이터 엔지니어에게 풍부한 데이터 소스이자 까다로운 과제를 동시에 안겨줍니다. Temu 상품 및 가격 데이터 스크래핑은 공식 API가 없기 때문에, 개발자는 HTML 카드 파싱과 내부 JSON 엔드포인트 호출 사이에서 전략을 결정해야 합니다.

이 글에서는 Temu의 안티봇 스택을 분석하고, 실제로 데이터가 어디에 숨겨져 있는지 보여주며, curl_cffi와 ProxyHat residential 프록시를 결합한 Python 구현 예제를 제공합니다. 끝에는 윤리적 고려사항과 FAQ까지 다룹니다.

Temu 스크래핑: API vs HTML 트레이드오프

Temu는 www.temu.com 도메인에서 Next.js 기반 SSR 페이지를 렌더링합니다. 공식 개발자 API나 가격 피드가 존재하지 않으므로, 데이터 수집자는 두 가지 접근법 중 하나를 선택해야 합니다.

  • HTML 파싱: <div class="_33e3..."> 같은 해시된 CSS 클래스를 가진 상품 카드를 직접 파싱합니다. 구현이 단순하지만, Temu가 클래스 해시를 자주 변경하면 셀렉터가 즉시 깨집니다.
  • 내부 JSON 엔드포인트: /api/poppy/v1/search (검색 결과)와 /api/poppy/v1/goods-detail (상품 상세) 같은 비공개 엔드포인트를 호출해 구조화된 JSON을 받습니다. HTML보다 안정적이지만, 서명된 anti_content 헤더와 토큰이 필요합니다.

대부분의 프로덕션 스크래퍼는 두 번째 접근법을 선호합니다. JSON은 스키마가 안정적이고 파싱 오버헤드가 적으며, 페이지 렌더링 대기 없이 더 빠르게 수집할 수 있기 때문입니다. 하지만 이 엔드포인트들은 Cloudflare Turnstile과 자체 서명 로직으로 보호되어 있어, 단순 requests.get() 호출로는 403 응답을 받게 됩니다.

내부 JSON 엔드포인트 구조

Temu의 프론트엔드는 페이지 로드 시 다음과 같은 엔드포인트를 호출합니다:

# 검색 결과 (카탈로그 페이지)
POST https://www.temu.com/api/poppy/v1/search?_p_jump_id=2&?list_page_key=...

# 상품 상세
POST https://www.temu.com/api/poppy/v1/goods-detail?goods_id=301902091234

요청 본문에는 searchKey, pageNum, pageSize 등의 필드와 함께 anti_content라는 서명 문자열이 포함되어야 합니다. 이 토큰은 브라우저의 동적 JS 실행 결과로 생성되며, 없으면 서버가 즉시 차단 응답을 반환합니다.

Temu 안티봇 스택 분석

Temu는 다층 안티봇 체계를 운영합니다. 이해하지 못하면 스크래핑이 불가능합니다.

1. Cloudflare Turnstile

Temu는 Cloudflare의 관리형 챌린지와 Turnstile 위젯을 사용합니다. Turnstile은 사용자 입력 없이 브라우저 환경을 검증하는 "invisible CAPTCHA"입니다. 단순 헤드리스 브라우저조차 Turnstile의 환경 검사(캔버스 핑거프린트, WebGL 렌더러, 자동화 흔적)에서 실패할 수 있습니다. Cloudflare에 따르면, Turnstile은 기존 CAPTCHA 대비 사용자 경험을 해치지 않으면서 봇을 차단하도록 설계되었습니다.

2. 서명된 anti_content 헤더/토큰

Temu의 가장 독특한 방어는 anti_content 토큰입니다. 이 값은 브라우저 측 JavaScript가 페이지 로드 시점의 환경 변수(타이밍, 디바이스 정보, 세션 상태 등)를 수집해 암호화 서명한 결과입니다. 각 API 요청마다 새 토큰이 필요하며, 재사용하면 서버가 거부합니다. 이 토큰을 생성하려면 실제 브라우저 환경에서 JS를 실행하거나, 토큰 생성 로직을 리버스 엔지니어링해야 합니다.

3. TLS/HTTP2 지문 — 데이터센터 IP 즉시 차단

Cloudflare는 JA3/JA4 TLS 지문과 HTTP/2 설정 프레임을 검사합니다. Python requests 라이브러리는 기본적으로 Chrome과 다른 TLS 핸드셰이크를 생성하므로, 데이터센터 IP에서 요청하면 첫 번째 패킷 단계에서 차단됩니다. AWS, GCP, DigitalOcean IP 대역은 Cloudflare의 IP 평판 데이터베이스에서 거의 즉시 플래그됩니다. 이것이 residential 프록시가 필수인 이유입니다.

방어 계층대상우회 전략
Cloudflare Turnstile브라우저 환경 검증Playwright/Patchright + stealth 플러그인
anti_content 토큰API 요청 서명브라우저에서 토큰 추출 또는 JS 리버스엔지니어링
TLS/HTTP2 지문클라이언트 핸드셰이크curl_cffi (impersonate=chrome120)
IP 평판데이터센터 IP 대역Residential 프록시 (도시 타겟팅)

데이터 위치: 숨겨진 JSON과 셀렉터

HTML 파싱을 선택하더라도, Temu 페이지에는 구조화된 데이터가 내장되어 있습니다. 다음 두 가지 소스를 활용할 수 있습니다.

__NEXT_DATA__ 스크립트 태그

Temu의 SSR 페이지는 <script id="__NEXT_DATA__" type="application/json"> 태그에 초기 상태를 주입합니다. 이 JSON 안에 상품 목록, 가격, SKU 정보, 이미지 URL이 포함되어 있습니다.

from bs4 import BeautifulSoup
import json, re

soup = BeautifulSoup(html, 'html.parser')
script = soup.find('script', id='__NEXT_DATA__')
data = json.loads(script.string)
# data['props']['pageProps']['store']['initialState'] 경로에 상품 데이터</nproducts = data['props']['pageProps'].get('store', {}).get('initialState', {}).get('goods', [])

이 방식은 페이지당 한 번의 요청으로 전체 상품 리스트를 얻을 수 있어 효율적입니다. 하지만 JSON 구조가 Temu 배포마다 변경될 수 있으므로, 깊은 경로 하드코딩보다는 동적 탐색이 안전합니다.

해시된 CSS 클래스와 data-uniqid

DOM에서 직접 상품 카드를 찾아야 할 때, Temu는 data-uniqid 속성을 사용합니다. 각 상품 카드에는 고유 ID가 부여되며, 이를 통해 상품을 식별할 수 있습니다.

# CSS 셀렉터 예시 (해시 클래스는 변경될 수 있음)
product_cards = soup.select('[data-uniqid]')
for card in product_cards:
    goods_id = card.get('data-uniqid')
    title_el = card.select_one('a[title]')
    title = title_el.get('title') if title_el else None
    # 가격은 __NEXT_DATA__에서 추출하는 것이 더 안정적

속도 제한과 Residential 프록시의 필요성

Temu는 공개적인 rate limit 문서를 제공하지 않지만, 실무 경험상 다음 임계값이 관찰됩니다:

  • 동일 IP당 약 30~50 요청/분 이상 전송 시 Cloudflare 챌린지 발생
  • 동일 IP에서 100 요청/분 초과 시 403 또는 429 응답
  • 반복 차단 시 IP가 24시간~72시간 쿨다운

더 중요한 것은 가격과 배송비가 지역별로 다르다는 점입니다. Temu는 사용자의 IP 기반 위치를 기준으로 가격, 재고, 배송비를 동적으로 조정합니다. 미국 캘리포니아에서 접속한 사용자와 독일 베를린에서 접속한 사용자에게 동일 상품의 가격이 다를 수 있습니다.

따라서 정확한 가격 인텔리전스를 위해서는 residential 프록시로 특정 국가/도시에서 요청을 보내야 합니다. ProxyHat의 -country-US 또는 -country-DE-city-berlin 플래그를 사용하면, 실제 ISP IP로 해당 지역 가격을 가져올 수 있습니다.

ProxyHat 요금제에서 residential 프록시 트래픽 비용을 확인하고, 지원 위치 목록에서 타겟 국가/도시 가용성을 확인하세요.

Python 구현: curl_cffi + ProxyHat으로 Temu 스크래핑

이제 실제 구현 예제를 살펴보겠습니다. 핵심 전략은 curl_cffi로 Chrome TLS 지문을 모방하고, ProxyHat residential 프록시로 IP 평판을 우회하는 것입니다.

필수 패키지 설치

pip install curl_cffi beautifulsoup4 lxml

상품 페이지 가져오기 + __NEXT_DATA__ 파싱

from curl_cffi import requests as cffi_requests
import json, re
from bs4 import BeautifulSoup

# ProxyHat residential 프록시 (미국 타겟팅)
proxy_url = 'http://user-country-US:pass@gate.proxyhat.com:8080'

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
                  'AppleWebKit/537.36 (KHTML, like Gecko) '
                  'Chrome/120.0.0.0 Safari/537.36',
    'Accept-Language': 'en-US,en;q=0.9',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
}

# impersonate='chrome120'으로 TLS/HTTP2 지문을 Chrome과 일치시킴
resp = cffi_requests.get(
    'https://www.temu.com/products/301902091234.html',
    headers=headers,
    proxies={'http': proxy_url, 'https': proxy_url},
    impersonate='chrome120',
    timeout=30,
)

if resp.status_code != 200:
    print(f'차단됨: {resp.status_code}')
    exit()

soup = BeautifulSoup(resp.text, 'html.parser')
script = soup.find('script', id='__NEXT_DATA__')
if script:
    data = json.loads(script.string)
    # 상품 정보 추출 (경로는 페이지 타입에 따라 다를 수 있음)
    page_props = data.get('props', {}).get('pageProps', {})
    goods = page_props.get('goods', page_props.get('store', {}).get('initialState', {}))
    print(json.dumps(goods, indent=2, ensure_ascii=False)[:500])

샘플 JSON 응답 (truncated)

{
  "goods_id": "301902091234",
  "goods_name": "Wireless Bluetooth Earbuds, IPX7",
  "salePrice": {
    "min": 12.98,
    "max": 18.99,
    "currency": "USD"
  },
  "skuList": [
    {
      "skuId": "sku_001",
      "skuName": "Black",
      "price": 12.98,
      "stock": 3421
    },
    {
      "skuId": "sku_002",
      "skuName": "White",
      "price": 13.49,
      "stock": 1280
    }
  ],
  "shippingInfo": {
    "shippingFee": 0.00,
    "estimatedDelivery": "5-8 days"
  },
  "rating": 4.6,
  "reviewCount": 12847
}

이 JSON에서 goods_id, salePrice, skuList를 추출해 자체 가격 모니터링 파이프라인에 적재할 수 있습니다.

Sticky 세션, 재시도, 페이지네이션

Sticky 세션으로 장바구니/배송 일관성 유지

Temu는 세션 쿠키를 기반으로 배송지와 가격을 결정합니다. 여러 요청에 걸쳐 동일 IP를 유지하지 않으면, 첫 번째 요청에서는 미국 가격을, 두 번째 요청에서는 다른 국가 가격을 받을 수 있습니다. ProxyHat의 -session- 플래그로 sticky 세션을 생성하세요.

# 동일 세션 ID로 여러 요청이 같은 IP로 라우팅
session_id = 'temu-session-abc123'
proxy_url = f'http://user-country-US-session-{session_id}:pass@gate.proxyhat.com:8080'

# 세션 유지하며 페이지네이션
for page in range(1, 11):
    resp = cffi_requests.get(
        f'https://www.temu.com/search_result.html?search_key=earbuds&page={page}',
        headers=headers,
        proxies={'http': proxy_url, 'https': proxy_url},
        impersonate='chrome120',
        timeout=30,
    )
    if resp.status_code == 200:
        parse_products(resp.text)
    else:
        # 재시도 로직
        retry_with_new_session(page)

재시도 전략

  • 403/429 응답 시 최소 5초 대기 후 재시도
  • 연속 3회 실패 시 새 세션 ID로 프록시 재할당
  • 지수 백오프: 5s → 15s → 45s → 120s
  • 최대 5회 재시도 후 해당 상품을 실패 큐에 적재

페이지네이션

Temu 검색 결과는 URL 파라미터 page=N으로 페이지네이션됩니다. 검색당 최대 약 50페이지까지 결과가 존재하며, 페이지당 약 30~50개 상품이 표시됩니다. 전체 카탈로그를 순회하려면 키워드별로 분할 수집하고, 각 키워드마다 별도 세션을 사용하는 것이 안전합니다.

더 자세한 웹 스크래핑 전략은 웹 스크래핑 사용 사례 페이지를 참고하고, SERP 기반 수집이 필요하면 SERP 추적 사용 사례도 확인하세요.

윤리 및 이용약관 고려사항

Temu 스크래핑은 기술적으로 가능하지만, 법적·윤리적 경계를 명확히 해야 합니다.

  • 공개 카탈로그 데이터만 수집: 로그인 없이 접근 가능한 상품명, 가격, 리뷰 수만 스크래핑합니다.
  • 계정 스크래핑 금지: 사용자 계정 데이터, 주문 내역, 개인정보는 CFAAGDPR 위반 소지가 큽니다.
  • robots.txt 준수: https://www.temu.com/robots.txt를 확인하고, 허용되지 않은 경로는 수집하지 않습니다.
  • 요청 속도 제어: 서버에 부하를 주지 않도록 초당 1~2 요청 이하로 유지합니다.
  • 공식 판매자 피드 우선: Temu 정식 판매자라면 Temu 셀러 센터에서 제공하는 판매자 API를 사용하는 것이 규정 준수 측면에서 안전합니다.

공개 데이터 수집은 일반적으로 합법적인 영역이지만, Temu의 이용약관(TOS)은 자동화 수집을 명시적으로 금지할 수 있습니다. 상업적 목적의 대규모 수집 전에는 법무팀 검토를 권장합니다.

ProxyHat 설정 가이드

ProxyHat으로 Temu 스크래핑 환경을 구성하는 단계를 정리합니다.

  1. 대시보드에서 인증 정보 확인: ProxyHat 대시보드에 로그인하여 사용자명과 비밀번호를 확인합니다.
  2. 프록시 유형 선택: Temu 스크래핑에는 residential 프록시를 사용합니다. 데이터센터 IP는 Cloudflare에 의해 즉시 차단됩니다.
  3. 지역 타겟팅: 수집하려는 시장의 가격을 정확히 가져오기 위해 -country-US, -country-DE-city-berlin 등의 플래그를 사용자명에 추가합니다.
  4. 세션 관리: -session-{id} 플래그로 sticky 세션을 유지하여, 동일 IP에서 일관된 가격/배송 정보를 가져옵니다.
  5. 동시성 제어: 동시 세션 수는 ProxyHat 플랜에 따라 제한됩니다. 공식 문서에서 최대 동시 연결 수를 확인하세요.
프록시 유형Temu 적합성이유
Datacenter❌ 부적합Cloudflare IP 평판에서 즉시 차단
Residential✅ 권장실제 ISP IP, 도시 타겟팅 가능, 가격 지역 차이 반영
Mobile✅ 대안높은 신뢰도, 비용이 다소 높음

핵심 요약 (Key Takeaways)

  • JSON 엔드포인트 우선: HTML 파싱보다 /api/poppy/v1/ JSON 엔드포인트가 안정적이지만, anti_content 토큰이 필요합니다.
  • curl_cffi 필수: impersonate='chrome120'으로 TLS/HTTP2 지문을 Chrome과 일치시켜야 Cloudflare를 통과합니다.
  • Residential 프록시 + 도시 타겟팅: 데이터센터 IP는 즉시 차단되며, 가격이 지역별로 다르므로 -country-US 플래그가 필수입니다.
  • Sticky 세션: -session- 플래그로 동일 IP를 유지해 장바구니/배송 일관성을 보장합니다.
  • 윤리적 경계: 공개 카탈로그 데이터만, 계정 스크래핑 금지, CFAA/GDPR 준수, 공식 판매자 API 우선.

Temu 상품 및 가격 데이터 스크래핑은 curl_cffi + residential 프록시 조합으로 충분히 달성 가능합니다. ProxyHat으로 지역별 가격 인텔리전스 파이프라인을 구축하려면 요금제를 확인하고, residential 프록시 트래픽을 시작하세요.

시작할 준비가 되셨나요?

AI 필터링으로 148개국 이상에서 5천만 개 이상의 레지덴셜 IP에 액세스하세요.

가격 보기레지덴셜 프록시
← 블로그로 돌아가기