亚马逊数据采集 API 技术选型:同步 vs 异步的边界在哪里?

0 阅读5分钟

异步亚马逊数据采集 vs 同步 API 调用模式对比示意图.png

TL;DR

  • 日均采集任务 < 100 次 且需要即时结果 → 同步 API,简单直接
  • 日均≥ 100 次 或有定时批量调度 → 异步 API,吞吐量 10x+
  • 两种模式积点消耗相同,技术能力决定选型,不是成本
  • Pangolinfo Scrape API 同一 token 同时支持两种接口

背景:为什么这个选型值得认真对待

在亚马逊数据基础设施建设中,异步亚马逊数据采集与同步调用的选型决策,很多团队在项目初期会因为"同步实现更简单"而默认选择同步——直到数据量增长到足以暴露瓶颈为止。

同步模式的问题在于,它的吞吐量上限被客户端线程数硬性约束。Amazon Scrape API 平均响应时间约 5 秒,单线程串行下 1000 个任务需要 83 分钟,10000 个任务就是 13.9 小时。当你的业务增长到这个量级时,系统已经在架构层面到达了天花板。

异步模式解除了这个约束——通过回调接收机制,服务端并行处理能力替代了客户端的串行等待,同样 1000 个任务可以在 5~10 分钟内完成。

这不是微优化,是吞吐量量级的跃迁。


核心原理:两种调用模型的底层差异

同步:阻塞 I/O,线程等待

你的程序         Pangolinfo 服务端
    │                    │
    │──── POST /scrape ──►│
    │         (阻塞约 5s)  │
    │                    │◄── 页面加载
    │                    │◄── 反爬绕过
    │                    │◄── DOM 解析
    │◄─── 返回 JSON 数据 ──│
    │                    │
  处理数据,发下一个请求

关键约束:吞吐量 = 并发线程数 / 平均响应时间

异步:非阻塞提交 + 回调接收

你的程序               Pangolinfo               你的回调服务
    │                       │                        │
    │── POST /scrape/async ─►│                        │
    │◄── 返回 taskId (200ms) │                        │
    │                       │── 后台并行处理 ──────────│
    │── 继续提交下一个任务 ..  │                        │
    │                       │── POST callbackUrl ────►│
    │                       │   (约 5s 后,结果数据)   │

核心突破:提交速率与处理速率解耦,吞吐量由服务端并发能力决定


代码实现:两种模式的关键差异

同步调用(适合实时/低量场景)

import requests

def sync_scrape_product(token: str, asin: str) -> dict:
    """同步采集商品详情 - 5秒后返回结果"""
    resp = requests.post(
        "https://scrapeapi.pangolinfo.com/api/v1/scrape",
        headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
        json={
            "url": f"https://www.amazon.com/dp/{asin}",
            "parserName": "amzProductDetail",
            "site": "", "content": "",
            "format": "json",
            "bizContext": {"zipcode": "10041"}
        },
        timeout=30
    )
    data = resp.json()
    if data["code"] == 0:
        return data["data"]["json"][0]["data"]["results"][0]
    raise ValueError(f"API error: {data['message']}")


# 用法
product = sync_scrape_product("your_token", "B0DYTF8L2W")
print(product["title"])  # 立即可用

异步调用(适合批量/定时场景)

import requests
import time

def async_submit(token: str, asin: str, callback_url: str) -> str:
    """异步提交采集任务 - 200ms 内返回 taskId"""
    resp = requests.post(
        "https://scrapeapi.pangolinfo.com/api/v1/scrape/async",
        headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
        json={
            "url": f"https://www.amazon.com/dp/{asin}",
            "callbackUrl": callback_url,
            "zipcode": "10041",
            "format": "json",
            "parserName": "amzProductDetail"
        },
        timeout=10
    )
    return resp.json()["data"]["data"]  # 返回 taskId


def bulk_async_submit(token: str, asins: list[str], callback_url: str) -> list[str]:
    """批量异步提交 - 几分钟内提交完数千个任务"""
    task_ids = []
    for i, asin in enumerate(asins):
        task_id = async_submit(token, asin, callback_url)
        task_ids.append(task_id)
        print(f"[{i+1}/{len(asins)}] {asin}{task_id}")
        time.sleep(0.1)  # 速率控制
    return task_ids


# 批量提交 5000 个 ASIN(几分钟内完成提交,之后等回调)
asins = [f"B{i:010d}" for i in range(5000)]  # 示例 ASIN 列表
task_ids = bulk_async_submit("your_token", asins, "https://your-server.com/callback")
print(f"已提交 {len(task_ids)} 个任务,等待回调...")


# 回调接收端(Flask 示例)
from flask import Flask, request, jsonify

app = Flask(__name__)
processed = set()  # 生产环境用 Redis 替代

@app.route("/callback", methods=["POST"])
def callback():
    data = request.get_json()
    task_id = data.get("taskId")
    
    # 幂等校验:防重复处理
    if task_id in processed:
        return jsonify({"code": 0, "message": "duplicate, skipped"})
    
    processed.add(task_id)
    results = data.get("data", {}).get("json", [{}])[0].get("data", {}).get("results", [])
    
    if results:
        product = results[0]
        # 写入数据库
        save_to_db(task_id, product)
    
    return jsonify({"code": 0, "message": "ok"})

亚马逊数据采集模式选择决策树

日均任务量 ≥ 100 次?
│
├── 否 → 需要立即返回数据给用户?
│         ├── 是 → 同步 API ✓(实时触发型)
│         └── 否 → 仍推荐同步(量少,异步基础设施成本不值)
│
└── 是 → 能部署公网可达的回调服务器?
          ├── 是 → 异步 API ✓(批量高效)
          └── 否 → 考虑 AMZ Data Tracker 可视化调度
                   或临时用同步 + 多线程并发提速

工程要点:异步模式的三个关键设计

1. 幂等控制(必须实现)

平台在网络抖动时可能重复投递同一个回调。用 taskId 作为唯一键,写库前校验是否已存在:

def idempotent_save(task_id: str, data: dict, db) -> bool:
    if db.exists("task", task_id):
        return False  # 已处理,跳过
    db.insert("task", {"id": task_id, "data": data})
    return True

2. 回调超时补偿(保证数据完整性)

import datetime

def check_pending_tasks(db, token: str, threshold_seconds: int = 60):
    """检查超时未回调的任务,触发同步补偿"""
    now = datetime.datetime.now()
    pending = db.query(
        "SELECT task_id, asin FROM tasks WHERE callback_received=0 "
        f"AND submitted_at < NOW() - INTERVAL {threshold_seconds} SECOND"
    )
    for task in pending:
        # 触发同步补偿查询
        result = sync_scrape_product(token, task["asin"])
        if result:
            db.update_task(task["task_id"], result)
            print(f"[COMPENSATED] {task['task_id']}")

3. 回调端点安全

import hmac
import hashlib

def verify_callback_auth(request_headers: dict, expected_token: str) -> bool:
    """验证回调来源合法性"""
    auth = request_headers.get("Authorization", "")
    return hmac.compare_digest(auth, f"Bearer {expected_token}")

连接到 Pangolinfo:两种接口无缝兼容

Pangolinfo Scrape API同一个 API token 即可调用同步和异步两套接口,无需额外注册或配置。支持以下 Amazon 数据场景:

  • amzProductDetail:商品详情(通过 ASIN 或 URL)
  • amzKeyword:关键词搜索结果
  • amzProductOfCategory:类目商品列表(Node ID)
  • amzProductOfSeller:卖家商品列表
  • amzBestSellers:热卖榜单
  • amzNewReleases:新品榜单

平台持续维护 Amazon 页面解析逻辑,DOM 结构变更无需修改你的代码。


总结

场景推荐模式理由
用户实时搜索触发同步需要立即返回
后台价格监控(>100/天)异步吞吐量需求
定时热卖榜抓取异步批量高效
单次 ASIN 验证查询同步简单直接
无服务器运维能力AMZ Data Tracker无代码调度

选对亚马逊异步 API 调用模式,是扩规模时最划算的架构投资。欢迎评论区讨论你的采集规模和技术栈。

#亚马逊数据采集 #API开发 #爬虫 #异步编程 #跨境电商