简介
做跨境外贸的朋友应该都比较熟悉亚马逊了,我就不多介绍了。
亚马逊的卖家平台最近开通了新的API,即SP-API。最近由于一些业务逻辑,需要调用这个API,费了很多周折,在此进行记录。
以往,卖家中心提供的都是MWS接口,不过这个接口年头已久,跟不上时代的节奏了,因此亚马逊开发了新版的基于REST的接口。不得不说,REST接口要比原有的MWS接口好用的多,不过相应的也变得复杂了。
亚马逊开发者中心现在完全不提供MWS的接口的申请了,新入门的开发者必须调用新版的SP-API接口了。这对于我们这些调包侠造成了很大的困扰。
在完成我的业务逻辑时,我发现目前网上开源的python的sp-api的客户端还没有,而亚马逊也只提供了一个基本是全英文版的文档,在这里,因此我就自己动手搞了一个,目前客户端已上传至pypi,各位如有需要可以随意使用。不过如果目前的客户端难以满足您的业务逻辑,需要额外的技术支持,可以联系panhaoyu.site@outlook.com获取付费技术支持。
客户端的配置使用
客户端的使用比较简单,根随亚马逊的文档进行一系列的配置就可以使用了。需要说明的是,这个文档提供了中文版本,不过中文版本的很多翻译和网站实际是对应不上的,因此建议参考英文文档进行配置。这个文档介绍的比较详细了,此处不赘述了。
我的这个客户端的使用应该也是比较简单的,如下所示。只要输入进去相应的配置项,就可以启动了。
这个客户端的一大亮点是,可以支持类型提示,也可以直接解析亚马逊返回的JSON字符串。在采用PyCharm等现代IDE进行开发的时候,可以省去不少的麻烦。
from datetime import datetime
import sp_api_clients
endpoint = "https://sellingpartnerapi-eu.amazon.com"
marketplace_id = "A1F83G8C2ARO7P"
refresh_token = ""
order_pk = 'xxx-xxxxxx-xxxxxxx'
role_arn = "arn:aws:iam::xxxxxxxxxxxx:role/wms_role"
aws_access_key = 'xxxxxxxxxxxx'
aws_secret_key = "xxxxx/xxxxxxxxxxxxxxxxxxxxx"
client_config = dict(
role_arn=role_arn,
endpoint=endpoint,
marketplace_id=marketplace_id,
refresh_token=refresh_token,
aws_access_key=aws_access_key,
aws_secret_key=aws_secret_key,
)
order_client = sp_api_clients.orders.OrdersClient(**client_config, use_cache=True)
orders = order_client.getOrders(
MarketplaceIds=[marketplace_id],
CreatedAfter=datetime(2000, 1, 1).isoformat()).payload.Orders
assert len(orders) > 0
assert orders[0].AmazonOrderId == order_pk
调用例子
这里作为博客,我再补充几个API调用实例。这里提供我获取订单列表和获取订单详情的一些代码吧,直接在项目里copy出来的,可读性我就不保证了。
获取订单列表
def synchronize(self, days: int = 30):
store = self.store
logger.info(f'Start synchronizing store {store.id}, auth={store.auth_id}, days={days}')
orders_client = self.orders_client
market_place = self.market_place
created_after = (datetime.now(tz=timezone.get_current_timezone()).date() - timedelta(days=days)).isoformat()
market_place_ids = [p.market_place_id for p in market_places.get_by_endpoint(market_place.endpoint)]
requested_orders: List[Order] = []
part = orders_client.getOrders(MarketplaceIds=market_place_ids, CreatedAfter=created_after).payload
requested_orders.extend(part.Orders)
while part.NextToken is not None:
part = orders_client.getOrders(MarketplaceIds=market_place_ids, CreatedAfter=created_after,
NextToken=part.NextToken).payload
requested_orders.extend(part.Orders)
# TODO double-deck for loop is slow, pay for optimization
for requested_order in requested_orders:
order_form, created = OrderFormModel.objects.using(self.using).get_or_create(
order_id=requested_order.AmazonOrderId, store=store)
order_form: OrderFormModel
order_form.transaction_status = self.ORDER_STATUS_MAP[requested_order.OrderStatus]
order_form.purchased_datetime = self.parse_datetime(requested_order.PurchaseDate)
order_form.order_earliest_ship_datetime = self.parse_datetime(requested_order.EarliestShipDate)
order_form.order_latest_ship_datetime = self.parse_datetime(requested_order.LatestShipDate)
order_form.order_earliest_delivery_datetime = self.parse_datetime(requested_order.EarliestDeliveryDate)
order_form.order_latest_delivery_datetime = self.parse_datetime(requested_order.LatestDeliveryDate)
order_form.order_updated_datetime = timezone.now()
requested_price = requested_order.OrderTotal
if requested_price is not None:
order_form.total_price_unit = self.CURRENCY_MAP.copy() \
.setdefault(requested_price.CurrencyCode, OrderFormModel.Currency.UNKNOWN)
order_form.total_price_value = float(requested_price.Amount)
while True:
try:
self.synchronize_order_form(order_form)
self.synchronize_finance(order_form)
break
except Exception as e:
logger.exception(e)
order_form.save()
获取订单信息
def synchronize_order_form(self, order_form: OrderFormModel):
logger.info(f'Start synchronizing order {order_form.id}, id={order_form.order_id}')
orders_client = self.orders_client
item_client = self.item_client
market_place = self.market_place
requested_items: List[OrderItem] = []
part = orders_client.getOrderItems(order_form.order_id).payload
requested_items.extend(part.OrderItems)
while part.NextToken is not None:
part = orders_client.getOrderItems(order_form.order_id).payload
requested_items.extend(part.OrderItems)
for requested_item in requested_items:
catalog_item = item_client.getCatalogItem(requested_item.ASIN, market_place.market_place_id).payload
try:
image_urls = [attr.SmallImage.URL for attr in catalog_item.AttributeSets]
except (TypeError, AttributeError):
image_urls = []
CommodityModel.objects.using(self.using).create(
order_form=order_form,
name=requested_item.Title, # 'Ledmasters Smoked Glass Pendant Light ... Industrial Ceiling'
sku=requested_item.SellerSKU, # 'iuu9iop455465'
external_id=requested_item.ASIN, # 'B01N7M3NWI'
count=requested_item.ProductInfo.NumberOfItems,
image_urls='\n'.join(image_urls),
)
如果这个客户端难以满足您的业务逻辑,可以联系panhaoyu.site@outlook.com获取付费技术支持。
这篇文章同时发布于我自己的博客。