亚马逊商品数据实时获取方案:API 接口开发与安全接入实践

在当今数字化电商时代,获取亚马逊商品的实时数据对于市场分析、竞品监控和商业决策至关重要。本文将深入探讨如何通过亚马逊 API 接口开发实现商品数据的实时获取,包括安全接入实践和完整的代码实现。

亚马逊 API 概述与接入准备

亚马逊提供了多种 API 接口供开发者使用,主要包括:

  1. 亚马逊产品 API(Product Advertising API) - 用于获取商品信息、价格、评论等数据
  2. 亚马逊卖家 API(Marketplace Web Service,MWS) - 面向卖家的 API,提供订单管理、库存管理等功能
  3. 亚马逊广告 API(Advertising API) - 用于管理亚马逊广告活动

本文主要聚焦于产品广告 API,因为它是获取商品详情最直接的方式。

接入亚马逊 API 前,需要完成以下准备工作:

  1. 注册账户(Associates Program)
  2. 申请 API 访问权限
  3. 获取 API 密钥(Access Key 和 Secret Key)
  4. 注册 AWS 账户(部分地区需要)
安全认证机制详解

亚马逊 API 使用 HMAC-SHA256 算法进行请求签名认证,这是一种安全的认证方式,确保请求的真实性和完整性。认证流程主要包括:

  1. 构建规范化请求字符串
  2. 创建待签名字符串
  3. 计算 HMAC-SHA256 签名
  4. 将签名添加到请求参数中

下面是一个完整的 Python 实现,展示如何构建和发送安全的请求到亚马逊 API:

import hashlib
import hmac
import time
import urllib.parse
import requests
from datetime import datetime
import logging
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
import os
from dotenv import load_dotenv

# 加载环境变量
load_dotenv()

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler("amazon_api.log"),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger("AmazonAPIClient")

class AmazonAPIClient:
    def __init__(self, access_key=None, secret_key=None, associate_tag=None, region='US', timeout=10, 
                 max_retries=3, backoff_factor=1):
        """初始化亚马逊API客户端"""
        # 从环境变量或参数获取凭证
        self.access_key = access_key or os.getenv("AMAZON_ACCESS_KEY")
        self.secret_key = secret_key or os.getenv("AMAZON_SECRET_KEY")
        self.associate_tag = associate_tag or os.getenv("AMAZON_ASSOCIATE_TAG")
        
        # 验证凭证
        if not all([self.access_key, self.secret_key, self.associate_tag]):
            raise ValueError("亚马逊API凭证不完整,请提供access_key, secret_key和associate_tag")
        
        self.region = region
        self.timeout = timeout
        self.max_retries = max_retries
        self.backoff_factor = backoff_factor
        
        # 创建会话并配置重试机制
        self.session = requests.Session()
        retry_strategy = Retry(
            total=max_retries,
            backoff_factor=backoff_factor,
            status_forcelist=[429, 500, 502, 503, 504],
            allowed_methods=["GET"]
        )
        adapter = HTTPAdapter(max_retries=retry_strategy)
        self.session.mount("https://", adapter)
        
        # 根据不同区域设置端点
        self.endpoints = {
            'US': 'webservices.amazon.com',
            'CA': 'webservices.amazon.ca',
            'UK': 'webservices.amazon.co.uk',
            'DE': 'webservices.amazon.de',
            'FR': 'webservices.amazon.fr',
            'IT': 'webservices.amazon.it',
            'ES': 'webservices.amazon.es',
            'JP': 'webservices.amazon.co.jp',
            'CN': 'webservices.amazon.cn',
            'IN': 'webservices.amazon.in'
        }
        
        self.endpoint = self.endpoints.get(region, self.endpoints['US'])
        
        # 设置请求头
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
            'Accept-Language': 'en-US,en;q=0.5',
            'Connection': 'keep-alive',
            'Upgrade-Insecure-Requests': '1',
        }
        
        logger.info(f"亚马逊API客户端初始化完成,区域: {region}, 端点: {self.endpoint}")
    
    def get_timestamp(self):
        """获取当前时间戳,格式为ISO 8601"""
        return datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')
    
    def sign_request(self, params):
        """使用HMAC-SHA256算法对请求进行签名"""
        # 添加必需的参数
        params['AWSAccessKeyId'] = self.access_key
        params['AssociateTag'] = self.associate_tag
        params['Timestamp'] = self.get_timestamp()
        params['Version'] = '2013-08-01'
        
        # 按照字典序排序参数
        sorted_params = sorted(params.items(), key=lambda x: x[0])
        
        # 构建规范化请求字符串
        canonical_query_string = '&'.join([f"{k}={urllib.parse.quote_plus(str(v))}" for k, v in sorted_params])
        
        # 创建待签名字符串
        string_to_sign = f"GET\n{self.endpoint}\n/onca/xml\n{canonical_query_string}"
        
        # 计算签名
        signature = hmac.new(
            self.secret_key.encode('utf-8'),
            string_to_sign.encode('utf-8'),
            hashlib.sha256
        ).digest()
        
        # 将签名转换为Base64编码
        signature = urllib.parse.quote_plus(signature.hex())
        
        # 添加签名到参数中
        params['Signature'] = signature
        
        return params
    
    def make_request(self, params):
        """发送签名后的请求"""
        # 签名请求
        signed_params = self.sign_request(params)
        
        # 构建请求URL
        query_string = '&'.join([f"{k}={urllib.parse.quote_plus(str(v))}" for k, v in signed_params.items()])
        url = f"https://{self.endpoint}/onca/xml?{query_string}"
        
        # 记录请求
        logger.info(f"发送请求: {url[:100]}..." if len(url) > 100 else f"发送请求: {url}")
        
        # 发送请求
        try:
            response = self.session.get(url, headers=self.headers, timeout=self.timeout)
            response.raise_for_status()
            
            # 记录请求成功
            logger.info(f"请求成功,状态码: {response.status_code}")
            return response.text
        except requests.exceptions.HTTPError as e:
            logger.error(f"HTTP错误: {e}")
            logger.error(f"响应内容: {response.text[:500]}..." if len(response.text) > 500 else f"响应内容: {response.text}")
            return None
        except requests.exceptions.ConnectionError as e:
            logger.error(f"连接错误: {e}")
            return None
        except requests.exceptions.Timeout as e:
            logger.error(f"请求超时: {e}")
            return None
        except requests.exceptions.RequestException as e:
            logger.error(f"请求异常: {e}")
            return None
    
    def get_item_info(self, asin, response_group='ItemAttributes,Offers,Images,Reviews'):
        """获取单个商品的详细信息"""
        params = {
            'Operation': 'ItemLookup',
            'ItemId': asin,
            'ResponseGroup': response_group
        }
        
        return self.make_request(params)
    
    def search_items(self, keywords, search_index='All', response_group='ItemAttributes,Offers,Images', 
                    sort='relevance', page=1):
        """搜索商品"""
        params = {
            'Operation': 'ItemSearch',
            'Keywords': keywords,
            'SearchIndex': search_index,
            'ResponseGroup': response_group,
            'Sort': sort,
            'ItemPage': str(page)
        }
        
        return self.make_request(params)
    
    def get_multiple_items(self, asins, response_group='ItemAttributes,Offers,Images,Reviews'):
        """批量获取多个商品的信息"""
        if not asins:
            logger.warning("未提供ASIN列表")
            return []
        
        # 限制每次请求的ASIN数量
        batch_size = 10
        results = []
        
        for i in range(0, len(asins), batch_size):
            batch = asins[i:i+batch_size]
            batch_asins = ','.join(batch)
            
            logger.info(f"批量请求商品信息,批次 {i//batch_size + 1}/{(len(asins)-1)//batch_size + 1}")
            xml_response = self.get_item_info(batch_asins)
            
            if xml_response:
                results.append(xml_response)
            
            # 避免请求过于频繁
            time.sleep(1)
        
        return results

# 使用示例
if __name__ == "__main__":
    # 从环境变量获取凭证
    # 或者直接在代码中提供(不推荐在生产环境中使用)
    ACCESS_KEY = os.getenv("AMAZON_ACCESS_KEY")
    SECRET_KEY = os.getenv("AMAZON_SECRET_KEY")
    ASSOCIATE_TAG = os.getenv("AMAZON_ASSOCIATE_TAG")
    
    if not all([ACCESS_KEY, SECRET_KEY, ASSOCIATE_TAG]):
        print("请设置环境变量或在代码中提供亚马逊API凭证")
        exit(1)
    
    # 创建API客户端
    client = AmazonAPIClient(
        access_key=ACCESS_KEY,
        secret_key=SECRET_KEY,
        associate_tag=ASSOCIATE_TAG,
        region='US',
        max_retries=3,
        backoff_factor=1
    )
    
    # 获取单个商品信息
    asin = "B07HGGYFZ6"  # 示例ASIN
    item_info = client.get_item_info(asin)
    if item_info:
        print(f"成功获取商品 {asin} 的信息")
        # 这里可以添加解析XML的代码
    
    # 搜索商品
    search_keywords = "wireless headphones"
    search_results = client.search_items(search_keywords)
    if search_results:
        print(f"成功获取搜索结果 (关键词: {search_keywords})")
        # 这里可以添加解析XML的代码
    
    # 批量获取多个商品信息
    asins = ["B07HGGYFZ6", "B07HGGYFZ7", "B07HGGYFZ8"]
    batch_results = client.get_multiple_items(asins)
    if batch_results:
        print(f"成功批量获取 {len(batch_results)} 个批次的商品信息")
        # 这里可以添加解析XML的代码

 

数据解析与处理

API 返回的是 XML 格式数据,需要安全地解析才能提取有用信息。下面是一个安全的数据解析器实现:<

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值