
前言
在亚马逊电商数据基础设施建设中,异步亚马逊数据采集与同步 API 调用的技术选型,直接影响系统的吞吐上限和运营时效。本文基于 Pangolinfo Amazon Scrape API 的真实接口文档,从底层机制、性能基准、工程实践三个维度,系统对比两种模式的差异,并提供可直接运行的 Python 完整示例。
适用读者:有一定 Python 开发经验、需要大规模采集亚马逊数据的工程师或技术团队。
目录
一、技术原理详解 {#原理}
1.1 同步调用:阻塞式请求-响应模型
同步 API 遵循标准 HTTP 请求语义:客户端发起 POST 请求后,线程阻塞直到服务端返回响应。对于 Amazon Scrape API,服务端需要完成以下流程:
客户端 → POST /api/v1/scrape
↓ (阻塞等待,约 5 秒)
服务端:页面加载 → 反爬绕过 → DOM 解析 → JSON 结构化
↓
客户端 ← 返回完整结构化数据
关键参数:平均响应时间 ~5s,每次调用消耗 1 积点(JSON 格式)。
1.2 异步调用:任务提交-回调接收模型
异步 API 采用完全不同的交互范式:
客户端 → POST /api/v1/scrape/async(携带 callbackUrl)
↓ (约 200ms,立即返回 taskId)
客户端 ← {"data": {"data": "e7da6144bed54df7a2891e98fdc8d517"}}
↓(服务端后台并行处理)
回调服务器 ← POST callbackUrl(结果数据,约 5s 后)
核心优势:客户端不阻塞,可立即提交下一个任务,服务端并发处理能力决定最终吞吐量。
二、接口参数对比 {#接口}
同步接口
请求地址:POST https://scrapeapi.pangolinfo.com/api/v1/scrape
| 参数 | 必填 | 说明 |
|---|---|---|
url | Yes | 目标页面 URL |
parserName | Yes | 解析器名称(见下表) |
site | Yes | 站点信息(有 url 可不填) |
content | Yes | 采集内容标识(ASIN/关键词等) |
format | Yes | 返回格式(json/rawHtml/markdown) |
bizContext | Yes | 业务上下文(含 zipcode) |
异步接口
请求地址:POST https://scrapeapi.pangolinfo.com/api/v1/scrape/async
| 参数 | 必填 | 说明 |
|---|---|---|
url | Yes | 目标页面 URL |
callbackUrl | Yes | 任务回调地址(POST 方式回传) |
format | Yes | 返回格式 |
parserName | Yes | 解析器名称 |
zipcode | Yes | 亚马逊邮编 |
支持的解析器
| parserName | 说明 |
|---|---|
amzProductDetail | 商品详情(ASIN) |
amzKeyword | 关键词搜索结果列表 |
amzProductOfCategory | 类目商品列表(Node ID) |
amzProductOfSeller | 卖家商品列表 |
amzBestSellers | 热卖榜 |
amzNewReleases | 新品榜 |
三、完整代码实现 {#代码}
3.1 同步调用完整实现(Python)
"""
Amazon Scrape API 同步调用完整示例
适用场景:实时触发、单次查询、任务量 < 100/天
"""
import requests
import json
from typing import Optional, Dict, Any
SYNC_API_URL = "https://scrapeapi.pangolinfo.com/api/v1/scrape"
def sync_scrape(
token: str,
url: str = "",
parser_name: str = "amzProductDetail",
site: str = "",
content: str = "",
format: str = "json",
zipcode: str = "10041"
) -> Optional[Dict[str, Any]]:
"""
同步调用 Amazon Scrape API
Args:
token: API 认证 token
url: 目标页面 URL(与 site+content 二选一)
parser_name: 解析器名称
site: 站点信息(与 url 二选一)
content: 采集内容(ASIN/关键词等)
format: 返回格式,json/rawHtml/markdown
zipcode: 亚马逊邮编
Returns:
解析后的数据字典,失败返回 None
"""
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
payload = {
"url": url,
"parserName": parser_name,
"site": site,
"content": content,
"format": format,
"bizContext": {"zipcode": zipcode}
}
try:
resp = requests.post(SYNC_API_URL, json=payload, headers=headers, timeout=30)
resp.raise_for_status()
result = resp.json()
if result.get("code") == 0:
return result["data"]["json"][0]["data"]["results"]
else:
print(f"[API ERROR] code={result.get('code')}, message={result.get('message')}")
return None
except requests.exceptions.Timeout:
print("[ERROR] 请求超时,同步接口平均响应 5s,建议设置 timeout=30")
return None
except requests.exceptions.RequestException as e:
print(f"[ERROR] 请求异常: {e}")
return None
if __name__ == "__main__":
TOKEN = "your_api_token_here"
# 通过 URL 采集商品详情
result = sync_scrape(
token=TOKEN,
url="https://www.amazon.com/dp/B0DYTF8L2W",
parser_name="amzProductDetail"
)
if result:
product = result[0]
print(f"商品标题: {product.get('title')}")
print(f"评分: {product.get('star')}")
print(f"销售排名: {product.get('bestSellersRank')}")
# 通过 site+content 采集关键词结果(无需拼接 URL)
keyword_result = sync_scrape(
token=TOKEN,
parser_name="amzKeyword",
site="amazon.com",
content="bluetooth headphones"
)
if keyword_result:
print(f"关键词结果数量: {len(keyword_result)}")
3.2 异步调用完整实现(Python)
"""
Amazon Scrape API 异步调用完整示例
适用场景:批量采集、定时调度、日均任务量 ≥ 100 次
"""
import requests
import time
import hashlib
from typing import Optional
from dataclasses import dataclass, field
from datetime import datetime
ASYNC_API_URL = "https://scrapeapi.pangolinfo.com/api/v1/scrape/async"
@dataclass
class TaskRecord:
"""任务状态记录(用于幂等控制和超时补偿)"""
task_id: str
asin: str
submitted_at: datetime = field(default_factory=datetime.now)
callback_received: bool = False
retry_count: int = 0
# 内存任务注册表(生产环境建议换成 Redis 或数据库)
TASK_REGISTRY: dict[str, TaskRecord] = {}
def submit_async_task(
token: str,
asin: str,
callback_url: str,
parser_name: str = "amzProductDetail",
zipcode: str = "10041",
format: str = "json"
) -> Optional[str]:
"""
提交单个异步采集任务
Returns:
task_id(成功)或 None(失败)
"""
payload = {
"url": f"https://www.amazon.com/dp/{asin}",
"callbackUrl": callback_url,
"zipcode": zipcode,
"format": format,
"parserName": parser_name
}
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
try:
resp = requests.post(
ASYNC_API_URL,
json=payload,
headers=headers,
timeout=10
)
result = resp.json()
if resp.status_code == 200 and result.get("code") == 0:
task_id = result["data"]["data"]
# 注册任务状态
TASK_REGISTRY[task_id] = TaskRecord(task_id=task_id, asin=asin)
print(f"[✓ SUBMITTED] ASIN={asin} → TaskID={task_id}")
return task_id
else:
print(f"[✗ FAILED] ASIN={asin}: code={result.get('code')}, msg={result.get('message')}")
return None
except requests.RequestException as e:
print(f"[✗ EXCEPTION] ASIN={asin}: {e}")
return None
def batch_submit(
token: str,
asin_list: list[str],
callback_url: str,
rate_limit_delay: float = 0.1
) -> dict[str, str]:
"""
批量提交异步任务
Args:
rate_limit_delay: 每次提交间隔(秒),避免触发速率限制
Returns:
{asin: task_id} 映射字典
"""
task_map = {}
total = len(asin_list)
print(f"开始批量提交 {total} 个 ASIN 采集任务...")
for i, asin in enumerate(asin_list, 1):
task_id = submit_async_task(token, asin, callback_url)
if task_id:
task_map[asin] = task_id
if i % 100 == 0:
print(f" 进度: {i}/{total}")
time.sleep(rate_limit_delay)
success_rate = len(task_map) / total * 100
print(f"\n批量提交完成: {len(task_map)}/{total} 成功 ({success_rate:.1f}%)")
return task_map
def handle_callback(task_id: str, payload: dict) -> bool:
"""
处理回调数据(在你的 callback 接收路由中调用此函数)
Args:
task_id: 任务 ID(用于幂等校验)
payload: 平台回调的 JSON 数据
Returns:
True: 处理成功 | False: 已处理过(重复投递)
"""
# 幂等校验:检查是否已处理
if task_id in TASK_REGISTRY and TASK_REGISTRY[task_id].callback_received:
print(f"[SKIP] TaskID={task_id} 已处理,忽略重复回调")
return False
# 提取数据
results = payload.get("data", {}).get("json", [{}])[0].get("data", {}).get("results", [])
if results:
product = results[0]
print(f"[✓ RECEIVED] TaskID={task_id}: {product.get('title', 'N/A')[:50]}...")
# 标记为已处理
if task_id in TASK_REGISTRY:
TASK_REGISTRY[task_id].callback_received = True
return True
if __name__ == "__main__":
TOKEN = "your_api_token_here"
CALLBACK_URL = "https://your-server.com/api/amazon/callback"
# 批量异步提交示例
asin_list = [
"B0DYTF8L2W", "B08N5LNQCX", "B07XJ8C8F5",
"B09G9FPHY6", "B0CMRK9PBM"
]
task_map = batch_submit(TOKEN, asin_list, CALLBACK_URL)
print(f"\n已注册任务: {list(task_map.values())}")
print("等待回调服务器接收结果...")
3.3 回调接收服务示例(Flask)
"""
简化版回调接收服务
生产环境建议使用 FastAPI + 异步处理 + 持久化存储
"""
from flask import Flask, request, jsonify
import logging
app = Flask(__name__)
logging.basicConfig(level=logging.INFO)
@app.route("/api/amazon/callback", methods=["POST"])
def receive_callback():
"""接收 Pangolinfo 异步采集回调"""
# 基础鉴权(生产环境从环境变量读取)
auth = request.headers.get("Authorization", "")
if auth != "Bearer your-callback-secret":
return jsonify({"code": 401, "message": "Unauthorized"}), 401
data = request.get_json(silent=True)
if not data:
return jsonify({"code": 400, "message": "Invalid payload"}), 400
task_id = data.get("taskId") or data.get("data", {}).get("taskId")
# 调用业务处理逻辑
success = handle_callback(task_id, data)
return jsonify({"code": 0, "message": "ok" if success else "duplicate"}), 200
if __name__ == "__main__":
# 本地开发:配合 ngrok http 5000 暴露到公网测试
app.run(port=5000, debug=True)
四、性能基准与成本分析 {#性能}
| 指标 | 同步模式 | 异步模式 |
|---|---|---|
| 单任务延迟 | ~5 秒 | 提交 <200ms |
| 1000 任务总耗时 | ~83 分钟(单线程) | 510 分钟(并发) |
| 积点消耗/次(JSON) | 1 点 | 1 点 |
| 基础设施成本 | 无额外要求 | 需要回调服务器 |
| 适合任务量 | < 100/天 | ≥ 100/天 |
五、常见问题与解决方案 {#faq}
Q1: 异步回调收不到数据怎么办?
A: 检查顺序:① callbackUrl 是否公网可达(用 curl 从外部测试)② 服务器防火墙是否开放对应端口 ③ 返回的 HTTP 状态码是否为 200(平台侧会记录回调失败并重试)。
Q2: 同一个任务收到了两次回调怎么处理?
A: 用 taskId 做幂等校验,写库前先 SELECT 查询是否已存在,存在则跳过。这是异步系统的标准防重设计。
Q3: 回调延迟比预期长很多?
A: Amazon 页面加载时间受目标站点负载和地区影响。建议在任务提交时记录 submitted_at,超过 2 倍平均响应时间(≈10 秒)未收到回调时,可触发同步补偿查询。
Q4: 同步调用 timeout 应该设多少?
A: 建议 timeout=30,预留 5 秒平均处理时间的 6 倍余量,覆盖 Amazon 页面偶发慢加载场景。
Q5: 可以同时使用同步和异步吗?
A: 完全可以,同一个 API token 两个接口都能用。常见模式:后台批量任务用异步,前端用户触发的实时查询用同步。
六、最佳实践建议 {#best-practices}
- 任务量评估先行:上线前估算日均任务峰值,超过 100 次直接用异步,省去后期重构成本。
- 回调幂等是基础:taskId 去重不是可选项,是必须实现的基础防重机制。
- 状态表兜底:任务状态表 + 超时自动补偿,是异步系统数据完整性的最后一道防线。
- 提交速率控制:批量提交时建议 100~200ms 间隔,避免触发 API 速率限制。
- 本地开发用 ngrok:
ngrok http 5000一行命令即可让本地服务接收回调,无需部署到服务器就能完整测试。
1887

被折叠的 条评论
为什么被折叠?



