TL;DR
OpenClaw 作为 AI Agent 执行框架,缺乏实时电商数据是其在跨境场景落地的最大障碍。接入 Pangolinfo API 能从根本上解决这一问题:API 直接返回结构化 JSON,避免了 DIY 爬虫的三重代价(反爬维护、Token 爆炸、规模天花板),让 OpenClaw 真正成为跨境运营团队的"数字员工"。
核心技能包(可直接安装):
git clone https://github.com/Pangolin-spg/openclaw-skill-pangolinfo.git
Tags: #api #python #ecommerce #automation
背景:AI Agent 框架在电商领域的落地困境
AI Agent 框架的核心价值在于任务自主规划 + 工具调用 + 结果反馈的闭环。这个闭环在许多领域已经有了不错的实践,但在跨境电商场景,它面临一个独特挑战:核心决策数据(竞品价格、BSR排名、评论情感)分散在受到强反爬保护的平台页面上,既无法稳定获取,获取后也难以直接供 LLM 消费。
多数开发者尝试了两条路:
路线A:让 AI 写爬虫 → 爬虫不稳定 → 投入大量精力维护 → 数据质量下降 → 项目搁浅
路线B:直接接入结构化数据 API → LLM 零负担消费 JSON → 工作流稳定运行 → 业务持续产出
两条路的结局直接决定了 AI Agent 在这个场景能否真正落地。
核心问题:为什么原始 HTML 会让 AI Agent 失效?
这需要从 LLM 的上下文消耗机制说起。
一个亚马逊商品详情页的原始 HTML 文档,典型体积在 300-600KB 之间。其中:
- 业务有效信息(价格、BSR、评分、Review数):约 2-4KB(< 1%)
- CSS 样式、JavaScript 逻辑、广告脚本、冗余标签:约 296-596KB(> 99%)
当这份文档被 tokenize 后输入给 LLM:
# 量化对比示例(基于 cl100k_base tokenizer,GPT-4o系列使用)
import tiktoken
enc = tiktoken.get_encoding("cl100k_base")
# 模拟原始 HTML 输入(450KB HTML 文档)
raw_html_sample = "..." # 实际 HTML 内容
html_tokens = len(enc.encode(raw_html_sample))
# 典型值:约 100,000 - 120,000 tokens
# Pangolinfo API 返回的结构化 JSON(同一商品)
structured_json_sample = """{
"asin": "B09XXXXX1",
"title": "Product Name",
"price": 29.99,
"currency": "USD",
"bsr": 847,
"bsr_category": "Home & Kitchen",
"rating": 4.3,
"review_count": 2847,
"availability": "In Stock",
"best_seller_badge": false,
"variations_count": 6
}"""
json_tokens = len(enc.encode(structured_json_sample))
# 典型值:约 80 - 120 tokens
print(f"原始 HTML Token 数:{html_tokens}") # ~110,000
print(f"结构化 JSON Token 数:{json_tokens}") # ~100
print(f"Token 消耗差异:{html_tokens / json_tokens:.0f}x") # ~1100x
结论:在最极端的情况下,原始 HTML 的 Token 消耗可以达到结构化 JSON 的 1000 倍以上。即使按保守的 100 倍计算,单次任务成本差异也达到两个数量级。
Pangolinfo API 在工程层面做了什么?
Pangolinfo 的价值在于它把数据工程中最难、最脏的部分——反爬穿透 + HTML 解析 + 字段标准化——全部封装在 API 内部,调用方看到的只有干净的 JSON。
这种设计在工程上被称为关注点分离(Separation of Concerns),是构建可维护 AI Agent 工作流的正确方式。
调用方(你的 OpenClaw 工作流)
│
│ POST /v1/amazon/product {"asin": "B09XXX", "marketplace": "US"}
│
▼
Pangolinfo API Layer
├── 反爬穿透层:住宅代理轮换 + TLS 指纹模拟 + 行为验证
├── 采集层:分布式浏览器渲染集群
├── 解析层:亚马逊专用领域解析模板(字段覆盖率 >95%)
└── 输出层:标准化 JSON / Markdown / 原始 HTML(可选)
│
│ {"asin": ..., "price": 29.99, "bsr": 847, ...}
▼
调用方收到干净 JSON,直接传入 LLM 推理层
完整工程实现
环境配置
# 克隆 OpenClaw Pangolinfo 技能包
git clone https://github.com/Pangolin-spg/openclaw-skill-pangolinfo.git
cd openclaw-skill-pangolinfo
pip install -r requirements.txt
# 复制并配置
cp config.example.yaml config.yaml
# 编辑 config.yaml,填入 PANGOLINFO_API_KEY
核心客户端实现(带重试逻辑)
import time
import requests
from typing import Optional, List, Dict, Any
from dataclasses import dataclass
@dataclass
class RetryConfig:
max_attempts: int = 3
backoff_factor: float = 2.0
status_forcelist: tuple = (429, 500, 502, 503, 504)
class PangolinfoClient:
"""
Pangolinfo Scrape API 生产级客户端
支持指数退避重试、字段过滤、批量请求
"""
BASE_URL = "https://api.pangolinfo.com/v1"
def __init__(self, api_key: str, retry_config: Optional[RetryConfig] = None):
self.headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
self.retry = retry_config or RetryConfig()
def _request(self, endpoint: str, payload: Dict[str, Any]) -> Dict:
"""带指数退避重试的 POST 请求"""
url = f"{self.BASE_URL}{endpoint}"
for attempt in range(self.retry.max_attempts):
try:
resp = requests.post(url, headers=self.headers,
json=payload, timeout=30)
if resp.status_code in self.retry.status_forcelist:
wait = self.retry.backoff_factor ** attempt
time.sleep(wait)
continue
resp.raise_for_status()
return resp.json()
except requests.exceptions.Timeout:
if attempt == self.retry.max_attempts - 1:
raise
time.sleep(self.retry.backoff_factor ** attempt)
raise RuntimeError(f"Failed after {self.retry.max_attempts} attempts")
def get_product(self, asin: str, marketplace: str = "US",
fields: Optional[List[str]] = None) -> Dict:
"""获取商品详情结构化数据"""
payload = {"asin": asin, "marketplace": marketplace}
if fields:
payload["fields"] = fields
return self._request("/amazon/product", payload)
def get_reviews(self, asin: str, marketplace: str = "US",
page: int = 1) -> Dict:
"""获取评论数据"""
return self._request("/amazon/reviews", {
"asin": asin, "marketplace": marketplace,
"page": page, "sort_by": "recent"
})
def get_bestseller(self, category_id: str,
marketplace: str = "US") -> Dict:
"""获取 BSR 榜单实时数据"""
return self._request("/amazon/bestseller", {
"category_id": category_id, "marketplace": marketplace
})
OpenClaw 工作流集成示例
import json
from datetime import datetime
# 竞品监控工作流(可直接注册为 OpenClaw 技能)
def monitor_competitors(api_key: str,
asin_list: List[str],
marketplace: str = "US") -> str:
"""
OpenClaw Skill: 批量监控竞品核心指标
返回值:供 LLM 分析的结构化报告字符串
LLM 基于此报告决策是否触发告警或策略调整
"""
client = PangolinfoClient(api_key)
results = []
for asin in asin_list:
# 只请求监控所需最小字段集,最大程度压缩 Token
data = client.get_product(
asin, marketplace,
fields=["price", "bsr", "rating", "review_count",
"availability", "best_seller_badge"]
)
data["asin"] = asin
data["fetched_at"] = datetime.utcnow().isoformat()
results.append(data)
# 输出紧凑 JSON 字符串,直接传入 OpenClaw LLM 决策层
return json.dumps(results, ensure_ascii=False, separators=(",", ":"))
# 评论情感数据采集(注册为 OpenClaw 技能)
def fetch_review_sentiment_data(api_key: str, asin: str,
marketplace: str = "US",
pages: int = 3) -> str:
"""
OpenClaw Skill: 采集评论数据供 LLM 情感分析
自动压缩字段,减少 Token 消耗
"""
client = PangolinfoClient(api_key)
all_reviews = []
for page in range(1, pages + 1):
data = client.get_reviews(asin, marketplace, page)
page_reviews = data.get("reviews", [])
if not page_reviews:
break
# 字段压缩:仅保留情感分析所需字段
for r in page_reviews:
all_reviews.append({
"r": r.get("rating"), # 评分
"t": r.get("title", "")[:100], # 标题(截断)
"b": r.get("body", "")[:400], # 正文(截断)
"v": r.get("verified_purchase"), # 是否已验证购买
"h": r.get("helpful_votes", 0) # Helpful 票数
})
return json.dumps({
"asin": asin,
"review_count": len(all_reviews),
"reviews": all_reviews
}, ensure_ascii=False, separators=(",", ":"))
最佳实践
1. 字段按需请求(减少 Token 浪费)
# 推荐:只请求当前业务场景所需字段
data = client.get_product("B09XXX", fields=["price", "bsr"])
# 不推荐:默认返回所有字段(Token 多消耗约 3x)
data = client.get_product("B09XXX")
2. 缓存慢变数据
import functools, time
@functools.lru_cache(maxsize=1000)
def cached_product_basic(asin: str, ttl_hour: int = 1) -> dict:
"""
对变化较慢的字段(商品标题、图片、类目)做缓存
避免重复计费,降低延迟
"""
# TTL 通过 time.time() // (ttl_hour * 3600) 控制缓存粒度
return client.get_product(asin, fields=["title", "category", "brand"])
3. 异常字段做 Fallback
def safe_get_bsr(data: dict) -> Optional[int]:
"""安全读取 BSR,处理缺失或格式异常"""
bsr = data.get("bsr")
if isinstance(bsr, int) and bsr > 0:
return bsr
return None # 让上层 LLM 决策层自行处理缺失数据
总结
| 方案 | 稳定性 | 规模性 | Token 成本 | 维护成本 | 推荐指数 |
|---|---|---|---|---|---|
| AI 手写爬虫 | 低 | 受限 | 极高(原始 HTML) | 极高 | ❌ |
| Pangolinfo API | 企业级 | 千万页面/天 | 极低(结构化 JSON) | 零 | ✅ |
完整技能包及最新示例代码:
GitHub - openclaw-skill-pangolinfo