Как работать с Amazon SP-API: инструкция для начинающих

в 5:15, , рубрики: amazon api, amazon aws, amazon sp-api, python

Этот текст я написал для людей, которые как и я, ещё 3 месяца назад про Python только слышали. Для тех, кто неплохо знает английский, но иногда хочет простого русского «ща сделаем». Для тех, кто решил написать свой первый запрос для API Amazon и не понимает, почему ничего не работает.

Писать скрипт для Amazon SP-API — это как пытаться собрать мебель из IKEA без инструкции: сначала ты рад, что купил новинку, а потом мучаешься, пытаясь понять, как это вообще работает. Вернее, в данном случае инструкции есть, но по словам самой же поддержки Amazon она «не полностью отражает возможности сервиса».

В этой статье я расскажу, как выполнить самый простой запрос на получения токена, сформировать любой доступный отчет (зависит от вашего «статуса»), выгрузить и правильно его прочитать.

Небольшое отступление. Возможно, название некоторых переменных, функций или чего бы то ни было ещё, покажутся вам странными. Прошу отнестись с пониманием — я умею писать на C#, но опыта с Python у меня мало и он на уровне«посмотрел два четырехчасовых ролика на Youtube». Я уверен, что можно что-то оптимизировать, использовать библиотеки и так далее. Но мы рассматриваем первые шаги, которые лично мне было крайне сложно сделать, потому что желание помогать у поддержки Amazon отсутствует, как и внятная инструкция на русском языке (а часто и на английском тоже). Все обсуждают отдельные ошибки, а не работу скриптов в целом.

Подготовка

Начать, конечно, следует с инструкции и регистрации. Все подробно описано по ссылке. Тут разбирать что-то отдельно не имеет смысла, это не относится к нашему скрипту. На что стоит обратить внимание: даже если вам дали доступ с вашей личной почтой gmail, mail и т.п. зарегистрировать аккаунт надо на рабочую почту, иначе вы не пройдете одобрение от Amazon. Да, существует возможность создания приложений если вы сторонний разработчик, но там отдельные заморочки с получением ключей и доступов. 

Следующий шаг — получить Restricted роли для работы с заказами. Эта роль позволит просматривать личные данные покупателя, например, ФИО и адрес. Для этого скрипта нам нужна только роль для составления отчетов (для вендоров это Brand Analytics). Но замечу, что ChatGPT неплохо справляется с ответами на анкету по ролям 🙂

После получения доступа картина выглядит так:

API integration

API integration

Отлично, жмем кнопку «Add new app client», заполняем название и тип API, указываем все доступные нам роли:

Возможные роли зависят от вашего запроса

Возможные роли зависят от вашего запроса

Из полученной записи нам понадобится несколько значений, а именно Client identifier и Client secret (они доступны, если нажать LWA credentials - View), а также Refresh Token (надо нажать стрелочку вниз рядом с кнопкой Edit App и выбрать вариант Authorise).

Куда нажать

Куда нажать
Данные для работы скрипта

Данные для работы скрипта

Шаг 1. Получение токена от Амазона

Около года назад Amazon внес некоторые изменения в свой API. Теперь нет необходимости настраивать AWS или получать дополнительный доступ —  все доступно прямо из вашего кабинета Sellers или Vendors Central. Это просто великолепно. URL для получения токена для всех маркетплейсов один — https://api.amazon.com/auth/o2/token. Для начала импортируем все, что нам понадобится:

import requests
import json
import time
import gzip
import pandas as pd

Далее пишем первую функцию для запроса ключа:

def get_access_token():
    url = 'https://api.amazon.com/auth/o2/token'
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded',
    }
    data = {
        "grant_type": "refresh_token",
            "refresh_token": "Atzr***", #Ваши данные из настроек
            "client_id": "amzn1.***", #Ваши данные из настроек
            "client_secret": "amz1.***" #Ваши данные из настроек
    }
    response = requests.post(url, headers=headers, data=data)
   
    if response.status_code == 200:
        return response.json()['access_token']
    else:
        raise Exception(f'Refresh token FAIL: {response.text}')

Ниже просто запускаем эту функцию:

access_token = get_access_token()

Можно ещё сделать print, чтобы проверить как она работает. На данном этапе в случае неудачи вы будете корректно получать сообщения об ошибке, система вполне адекватно ответит, если вы забыли какой-то ключ.

Шаг 2. Функция для запроса отчета

На Амазоне можно продавать по нескольким разным схемам. Я работаю в компании-вендоре, это B2B-сегмент. Наши отчеты сильно ограничены относительно стандартных селлеров, но всё же что-то сделать можно. Список всех отчетов тут. Я буду использовать GET_VENDOR_INVENTORY_REPORT. Подробнее про него можно почитать тут.

Приступим. Для начала нам понадобится URL, на который мы хотим отправить запрос. Их несколько, для евро-региона мы используем sellingpartnerapi-eu.amazon.com. Список доступен по ссылке.

Берем URL, добавляем к нему часть про отчеты и ID вашего маркетплейса, не забываем передать в функцию полученный токен из первого шага. Маркетплейсы можно глянуть либо в настройках, либо по ссылке.

def get_vendor_inventory_report(access_token):
    url = f'https://sellingpartnerapi-eu.amazon.com/reports/2021-06-30/reports'
    headers = {
        'Content-Type': 'application/json',
        'x-amz-access-token' : access_token
    }
    body = json.dumps({
        'reportType': 'GET_VENDOR_INVENTORY_REPORT',
        'marketplaceIds': ['A1PA6795UKMFR9'], #Здесь ваш Макретплейс ID
        "reportOptions":{"reportPeriod": "DAY",
                         "distributorView": "MANUFACTURING", 
                         "sellingProgram": "RETAIL"}, 
        'dataStartTime': '2024-10-21',  
        'dataEndTime': '2024-10-21',  
    })
   
    response = requests.post(url, headers=headers, data=body)
   
    if response.status_code == 202:
        print("Starting report preparations!")
        reportId = response.json()['reportId']
        return reportId
    else:
        print("Report FAIL", response.text)
        return None

Дописываем запуск:

access_token = get_access_token()
reportId = get_vendor_inventory_report(access_token)

Обратите внимание на даты dataStartTime и dataEndTime. У Амазона есть требования к датам, например, нельзя указывать в качестве даты старта воскресенье или отчет можно запросить только за вчера. Читайте внимательно описание отчета.

Второе – тут мы только запрашиваем отчет у системы. Сам отчет мы будем получать попозже.

Отлично, теперь у нас есть reportID, который будем использовать в следующем шаге.

Шаг 3. Дожидаемся отчета

После запроса отчета из предыдущего шага, необходимо дождаться, когда он будет готов. Для этого пишем новую функцию:

def get_response_information(access_token, reportId):
    url = f'https://sellingpartnerapi-eu.amazon.com/reports/2021-06-30/reports/' + reportId
    headers = {
        'Content-Type': 'application/json',
        'x-amz-access-token' : access_token,
        'x-amzn-RequestId' : reportId
    }
   
    response = requests.get(url, headers=headers)

    while response.json()['processingStatus'] not in ['DONE', 'FATAL']:
        print('Report in queue, stay tuned...')
        print(response.json()['processingStatus'])
        time.sleep(5)
        response = requests.get(url, headers=headers)

    status = response.json()['processingStatus']
    print("Report status: ", status)
    reportDocumentID = response.json()['reportDocumentId']
   
    return reportDocumentID

В этой функции мы просто ожидаем, пока Амазон ответит нам. Возможно появление нескольких статусов, основные — это DONE и FATAL. Первый говорит о том, что наш запрос готов и его можно скачивать, второй — что что-то пошло не так. И вот тут кроется одна из проблем, которую я никак не мог решить. Дело в том, что ответ содержится в gzip архиве. В следующих шагах мы рассмотрим, как его прочитать, но надо учитывать, что ответ может быть в формате «Неправильно заданы даты» или «Запрос недействителен». Конкретную ошибку в запросе вам не напишут, только общую информацию. Добро пожаловать на гитхаб или реддит, там полно обсуждений ошибок отчетов. Но не будем о грустном, главное, что в конце мы получили ID готового документа. Дописываем выполнение и переходим к следующему шагу.

access_token = get_access_token()
reportId = get_vendor_inventory_report(access_token)
time.sleep(5)
reportDocumentID = get_response_information(access_token, reportId)

Замечу, что я тут добавил таймер сна на пять секунд, потому что можно столкнуться с ограничением в количестве запросов, отправляемых в API. Для нас он на уровне двух запросов в секунду, но я прочитал, что best practices — давать отдых в секунду после предыдущего запроса. В данном случае сделал пять.

Шаг 4. Получение ссылки на отчет

Снова отправляем запрос. На этот раз меняем ссылку, документы лежат в другом месте – reports/2021-06-30/documents:

def get_report_document(access_token, reportDocumentID):
    url = f'https://sellingpartnerapi-eu.amazon.com/reports/2021-06-30/documents/' + reportDocumentID
    headers = {
        'Content-Type': 'application/json',
        'Accept-Encoding': 'application/json',
        'x-amz-access-token' : access_token,
        'reportDocumentId' : reportDocumentID
    }
   
    response = requests.get(url, headers=headers)
    documentUrl = response.json()['url']

    return documentUrldef get_report_document(access_token, reportDocumentID):
    url = f'https://sellingpartnerapi-eu.amazon.com/reports/2021-06-30/documents/' + reportDocumentID
    headers = {
        'Content-Type': 'application/json',
        'Accept-Encoding': 'application/json',
        'x-amz-access-token' : access_token,
        'reportDocumentId' : reportDocumentID
    }
   
    response = requests.get(url, headers=headers)
    documentUrl = response.json()['url']


    return documentUrl

Независимо от статуса отчета, ссылку на документ вам отдадут. Тут я столкнулся с новый проблемой. Мы можем вывести эту ссылку в консоль, в небо или куда угодно, но при открытии ссылки будут только кривые символы. У ребят с Youtube, которых я смотрел, открывается в нормальном виде. Возможно, у них есть расширения для хрома или я просто не обладаю опытом, но без скачивания этого архива я его посмотреть не смог. Да, не забываем дописывать запуск:

access_token = get_access_token()
reportId = get_vendor_inventory_report(access_token)
time.sleep(5)
reportDocumentID = get_response_information(access_token, reportId)
time.sleep(5)
url = get_report_document(access_token, reportDocumentID)

Шаг 5. Скачиваем архив с нашими данными.

Тут обработка несложная. Мы просто открываем ссылку и пакуем всю информацию в архив. Работать с файлами пока особо не будем, просто укажем самое очевидное место:

def get_report_information(url, file):  
    file = "file.gzip"
    try:
        response = requests.get(url)

        if response.status_code == 200:
            with open(file, 'wb') as file:
                file.write(response.content)
                print(f'File ready!')
        else:
            print(f'Download file error: {response.status_code}')
   
    except Exception as e:
        print(f'ERROR: {e}')  

Все, мы закончили. Все молодцы. А да, еще дописать запуск.

access_token = get_access_token()
reportId = get_vendor_inventory_report(access_token)
time.sleep(5)
reportDocumentID = get_response_information(access_token, reportId)
url = get_report_document(access_token, reportDocumentID)
time.sleep(5)
get_report_information(url)

Получив наконец свой долгожданный отчет, я задумался: а не стоит ли написать новый скрипт, который будет сообщать мне, когда заканчиваются запасы кофе у нас на кухне? В конце концов, если я уже прошел через ад Amazon SP-API. За этим простым скриптом стоит несколько дней изучения и плотной работы с различными источниками.

ЧаВо

Есть библиотека, почему ты не использовал ее?

Мне сложно использовать готовые библиотеки, когда я не понимаю до конца, как они работают. Готовая библиотека SP-API существует, но описанные в статье шаги она не сильно упростит.

Твой код некрасивый, ты не мог бы сделать иначе?

Мог бы и уже сделал. Но для человека, только начинающего свой путь в разработке на Питоне этого было достаточно. Но я совершенно не обижаюсь на код-ревью. Если что-то сильно бесит — обязательно напиши в комментах.

Почему не на английском?

Мой уровень позволяет обсуждать рабочие темы и вопросы с людьми из Германии, Франции и Италии. Но при подготовке этого простого скрипта я по 8 часов в день был погружен в английский. В какой-то момент я подумал, что было бы здорово иметь такую инструкцию на русском.

Ключи находятся в открытом доступе?

Для данного примера и первого запроса – да. Но в будущем все они перенесены в зашифрованный файл, мы рассматриваем простой запрос для начала.

Что дальше?

Дальше работа с файлами. Отчет можно прочитать, взять из него нужные данные по количеству и цене. Потом можно обновить все продукты другим скриптом и так далее. Все, что может позволить SP-API перед вам в инструкции.

Автор: Anan_Ass

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js