如果你在2026年试图抓取Temu产品与价格数据,你会立刻面对一个根本性抉择:解析易变的HTML卡片,还是直接请求内部JSON端点。Temu没有提供公开的商品API,这意味着所有数据采集都必须逆向其前端架构。本文将带你从反爬机制到代码实现,完整走通一条可用的采集路径。
2026年如何抓取Temu产品与价格数据:先做架构选型
Temu的前端是一个高度动态的Next.js应用。商品列表页和详情页的DOM中,CSS类名经过哈希混淆(如 css-1a2b3c),每次发版都可能变化。直接用CSS选择器解析HTML虽然可行,但维护成本极高——一次前端更新就可能让你的抓取脚本全面失效。
更可靠的策略是找到页面背后的JSON数据源。Temu的搜索和详情页在加载时会请求内部API端点,例如 /api/poppy/v1/search 和商品详情接口。这些端点返回结构化JSON,字段稳定,远比HTML解析耐用。但代价是:这些端点有严格的反爬保护。
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| HTML解析(BeautifulSoup/lxml) | 入门简单,不依赖逆向 | 类名哈希易变,维护成本高 | 小规模一次性抓取 |
| 内部JSON端点 | 字段稳定,数据完整 | 需要逆向签名头,反爬严格 | 持续价格监控、批量采集 |
| 嵌入式__NEXT_DATA__ | 无需额外请求 | 仅首屏数据,分页仍需API | 快速获取单页摘要 |
Temu的反爬技术栈:为什么数据中心IP会被秒封
Temu部署了多层反爬体系,理解每一层是成功抓取的前提:
1. Cloudflare Turnstile与JS挑战
Temu使用 Cloudflare Turnstile 作为前置防护。它会在浏览器中执行JS挑战,验证客户端是否为真实浏览器。对于无法执行JS的HTTP客户端,Cloudflare会返回403或挑战页面。Turnstile还会检查TLS指纹和HTTP/2设置帧,非浏览器客户端的指纹特征会被标记。
2. 签名头 anti_content
Temu的API请求需要携带一个 anti_content 头部(有时也以 anti_token 形式出现)。这是一个在前端JS中生成的签名令牌,包含时间戳、设备指纹和行为特征。没有有效签名的请求会被直接拒绝。逆向这个签名是抓取的核心难点——它由混淆JS生成,逻辑频繁更新。
3. TLS/HTTP2指纹检测
即使你伪造了User-Agent和Cookie,TLS握手阶段的ClientHello信息包和HTTP/2 SETTINGS帧仍然会暴露你的真实身份。Python requests 库的TLS指纹与Chrome完全不同,Cloudflare能在一秒内识别。根据 RFC 9113 对HTTP/2的规范,不同客户端的帧顺序和设置值存在可检测差异。
4. 数据中心IP即时标记
Cloudflare维护一个IP信誉数据库,数据中心IP段(AWS、GCP、DigitalOcean等)会被自动标记为高风险。来自这些IP的请求会触发更严格的挑战,甚至直接封禁。这就是为什么住宅代理是抓取Temu的必需品,而非可选项。
定位数据:隐藏JSON与端点结构
嵌入式状态数据
Temu的商品页面在HTML中嵌入了一个类似 __NEXT_DATA__ 的状态块。你可以在页面源码中搜索 <script id="__NEXT_DATA__" 或类似模式,提取其中的JSON。这个块包含了首屏渲染所需的商品基本信息:标题、价格、SKU列表、图片URL等。
<script id="__NEXT_DATA__" type="application/json">
{"props":{"pageProps":{"goods":{
"goods_id": "2090999xxxx",
"title": "Wireless Earbuds Pro",
"salePrice": {"amount": 12.99, "currency": "USD"},
"skuList": [
{"skuId": "sku_001", "color": "Black", "stock": 120},
{"skuId": "sku_002", "color": "White", "stock": 0}
]
}}}}
</script>
注意 data-uniqid 属性——Temu在商品卡片上使用这个属性标识每个商品,可以作为HTML解析时的稳定锚点,比哈希类名可靠得多。
内部JSON端点
搜索列表和分页数据通过 /api/poppy/v1/search 加载。关键参数包括:
searchKey— 搜索关键词pageNum/pageSize— 分页控制anti_content— 签名令牌(必需)search_id— 搜索会话标识
商品详情则通过类似 /api/poppy/v1/goods/detail 的端点获取,传入 goods_id 即可返回完整SKU、价格和物流信息。端点URL和参数名可能随版本变化,建议用浏览器DevTools的Network面板抓包确认最新路径。
速率限制与住宅代理的地理定位
Temu对API请求有隐性速率限制。根据实测,同一IP在短时间内发送超过约20-30次/分钟的API请求就可能触发临时封禁(返回429或空响应)。更关键的是,Temu的价格和运费会根据用户地理位置动态变化——美国用户看到的价格和日本用户看到的价格可能不同,部分地区还有免运费门槛。
这意味着你的代理IP必须与目标市场匹配。如果你要监控美国市场定价,就需要使用美国住宅IP。ProxyHat支持国家级和城市级地理定位:
# 美国住宅代理(国家级)
http://user-country-US:pass@gate.proxyhat.com:8080
# 德国柏林住宅代理(城市级)
http://user-country-DE-city-berlin:pass@gate.proxyhat.com:8080
# 日本住宅代理
http://user-country-JP:pass@gate.proxyhat.com:8080
城市级定位在需要精确模拟特定地区用户行为时非常有用。例如,Temu对偏远地区的运费计算可能与大城市不同,城市级IP能更准确反映真实展示价格。ProxyHat覆盖190+国家/地区的住宅IP池,你可以在 代理位置页面 查看完整列表。
Python实战:用curl_cffi + ProxyHat抓取Temu商品数据
要绕过TLS指纹检测,标准 requests 库不够用。推荐使用 curl_cffi,它基于libcurl的TLS模拟功能,能伪装成Chrome的TLS指纹。
安装依赖
pip install curl_cffi beautifulsoup4 lxml
抓取商品详情页并解析嵌入JSON
from curl_cffi import requests as cffi_requests
import json, re
# ProxyHat住宅代理 - 美国IP
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/131.0.0.0 Safari/537.36",
"Accept-Language": "en-US,en;q=0.9",
}
# impersonate参数模拟Chrome的TLS/HTTP2指纹
response = cffi_requests.get(
"https://www.temu.com/goods-detail-2090999xxxx.html",
headers=headers,
proxies={"http": proxy_url, "https": proxy_url},
impersonate="chrome131",
timeout=30,
)
# 提取嵌入式JSON状态块
match = re.search(
r'<script[^>]*id="__NEXT_DATA__"[^>]*>(.*?)</script>',
response.text,
re.DOTALL,
)
if match:
data = json.loads(match.group(1))
goods = data["props"]["pageProps"]["goods"]
print(f"商品ID: {goods['goods_id']}")
print(f"标题: {goods['title']}")
print(f"价格: ${goods['salePrice']['amount']}")
for sku in goods.get("skuList", []):
print(f" SKU: {sku['skuId']} | {sku.get('color','')} | 库存: {sku['stock']}")
else:
print("未找到嵌入数据,可能被Cloudflare拦截")
截断的示例JSON响应
{
"goods_id": "2090999xxxx",
"title": "Wireless Earbuds Pro, Bluetooth 5.3",
"salePrice": {"amount": 12.99, "currency": "USD", "minAmount": 10.99},
"originPrice": {"amount": 29.99, "currency": "USD"},
"skuList": [
{"skuId": "sku_001", "color": "Black", "stock": 120, "price": 12.99},
{"skuId": "sku_002", "color": "White", "stock": 0, "price": 12.99}
],
"shippingInfo": {"freeThreshold": 5.90, "estimatedDays": "5-10"},
"rating": 4.6,
"soldCount": 15234
}
调用内部搜索API端点
from curl_cffi import requests as cffi_requests
import json
proxy_url = "http://user-country-US:pass@gate.proxyhat.com:8080"
# 注意:anti_content需要从浏览器抓包获取或逆向生成
# 这里假设你已通过其他方式获取了有效签名
search_payload = {
"searchKey": "wireless earbuds",
"pageNum": 1,
"pageSize": 50,
"anti_content": "YOUR_ANTI_CONTENT_TOKEN_HERE",
"search_id": "search_session_001",
}
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/131.0.0.0 Safari/537.36",
"Content-Type": "application/json",
"Origin": "https://www.temu.com",
"Referer": "https://www.temu.com/search_result.html",
}
response = cffi_requests.post(
"https://www.temu.com/api/poppy/v1/search",
json=search_payload,
headers=headers,
proxies={"http": proxy_url, "https": proxy_url},
impersonate="chrome131",
timeout=30,
)
result = response.json()
items = result.get("data", {}).get("list", [])
for item in items[:5]:
print(f"{item['goods_id']} | ${item['salePrice']} | {item['title'][:40]}")
粘性会话、重试与分页策略
粘性会话保证数据一致性
当你需要连续抓取一个商品的详情页、SKU变体和运费信息时,如果每次请求都切换IP,Temu可能返回不同地区的价格和库存。使用ProxyHat的粘性会话(sticky session)可以确保一系列请求来自同一个IP:
# 粘性会话 - 同一IP保持最多30分钟
sticky_proxy = "http://user-country-US-session-temu_abc123:pass@gate.proxyhat.com:8080"
# 第1次请求:商品详情
resp1 = cffi_requests.get(
"https://www.temu.com/goods-detail-2090999xxxx.html",
proxies={"http": sticky_proxy, "https": sticky_proxy},
impersonate="chrome131",
timeout=30,
)
# 第2次请求:SKU库存(同一IP,数据一致)
resp2 = cffi_requests.post(
"https://www.temu.com/api/poppy/v1/goods/sku",
json={"goods_id": "2090999xxxx"},
proxies={"http": sticky_proxy, "https": sticky_proxy},
impersonate="chrome131",
timeout=30,
)
-session- 标志后跟自定义ID,ProxyHat会将该ID绑定到一个固定IP。这对于购物车模拟、运费计算和多步API调用至关重要。
重试与指数退避
import time, random
def fetch_with_retry(url, max_retries=3, **kwargs):
for attempt in range(max_retries):
try:
resp = cffi_requests.get(url, impersonate="chrome131", timeout=30, **kwargs)
if resp.status_code == 200:
return resp
elif resp.status_code == 429:
wait = (2 ** attempt) + random.uniform(1, 3)
print(f"429限流,等待{wait:.1f}秒...")
time.sleep(wait)
elif resp.status_code == 403:
print("Cloudflare拦截,更换会话ID")
# 生成新session ID以切换IP
kwargs["proxies"] = {k: v.replace("temu_abc123", f"temu_{attempt}")
for k, v in kwargs.get("proxies", {}).items()}
time.sleep(5)
else:
print(f"HTTP {resp.status_code}")
time.sleep(2)
except Exception as e:
print(f"请求异常: {e}")
time.sleep(5)
return None
分页控制
搜索结果分页时,每页请求间隔建议保持在3-5秒。同时,每次翻页应更换session ID以使用新IP,避免单IP请求过多触发限流:
for page in range(1, 11): # 抓取前10页
session_id = f"temu_page_{page}"
proxy = f"http://user-country-US-session-{session_id}:pass@gate.proxyhat.com:8080"
payload = {
"searchKey": "wireless earbuds",
"pageNum": page,
"pageSize": 50,
"anti_content": get_anti_content(), # 你的签名生成函数
}
# ... 发送请求并解析 ...
time.sleep(random.uniform(3, 5))
常见错误与边缘情况
- anti_content过期:签名令牌通常有时效性(约5-10分钟),超时后请求会被拒绝。需要定期刷新。
- 价格因地区不同:同一商品在不同国家的展示价格可能差异10%-30%。务必用目标市场的代理IP。
- SKU库存为0不代表下架:Temu的库存数据可能因地区不同而异,某地区缺货不代表全球缺货。
- Cloudflare挑战页:如果响应HTML中包含
cf-challenge或turnstile关键词,说明被拦截。检查TLS模拟参数是否匹配最新Chrome版本。 - 移动端与桌面端数据差异:Temu移动端页面结构不同,价格和促销可能也不同。根据需求选择对应的User-Agent和页面URL。
合规与道德边界
抓取公开目录数据在多数司法管辖区属于合法行为,但必须遵守以下原则:
- 仅采集公开可见的商品目录数据:商品名称、价格、图片、评分等公开展示的信息。
- 不抓取用户账户数据:不登录、不采集个人信息、不绕过登录墙。这涉及 COPPA 和GDPR等隐私法规。
- 遵守robots.txt:检查
https://www.temu.com/robots.txt,尊重其爬取规则。 - 控制请求频率:合理限速,不对目标服务器造成压力。
- 遵守服务条款:仔细阅读Temu的TOS。虽然公开数据抓取受CFAA判例保护(如
hiQ v. LinkedIn),但违反TOS仍有法律风险。 - 优先使用官方渠道:如果你是Temu商家,应优先使用官方商家后台的数据导出功能或API,而非爬虫。
核心原则:采集公开商品数据用于价格情报和市场分析是合理使用场景,但不应大规模复制竞品完整目录用于转售。
ProxyHat配置与相关资源
ProxyHat提供住宅、移动和数据中心代理。对于Temu抓取,住宅代理是唯一推荐选择,因为数据中心IP会被Cloudflare即时标记。配置步骤:
- 在 ProxyHat定价页 选择住宅代理套餐。
- 在控制面板中获取你的用户名和密码。
- 在用户名中添加地理定位和会话参数。
- 将代理配置集成到你的抓取脚本中。
更多抓取场景可以参考 网页抓取用例 和 SERP追踪用例。完整的技术文档请访问 ProxyHat官方文档。
关键要点总结
- 优先用JSON端点而非HTML解析:
/api/poppy/v1/search和商品详情端点返回结构化数据,比哈希类名HTML稳定得多。 - TLS指纹是第一道门槛:用
curl_cffi的impersonate参数模拟Chrome指纹,否则连Cloudflare第一关都过不了。 - 住宅代理 + 地理定位是必需品:数据中心IP会被秒封,且价格因地区不同,必须用
-country-US等参数匹配目标市场。 - 粘性会话保证数据一致性:连续API调用使用
-session-参数绑定同一IP。 - anti_content签名是核心难点:需要定期从浏览器抓包或逆向JS获取。
- 合规底线:仅采集公开目录数据,不登录、不抓取个人信息、控制请求频率。
准备好开始抓取Temu数据了吗?前往 ProxyHat定价页 选择适合你规模的住宅代理套餐,或查看 全球IP位置 确认覆盖范围。






