Сравнение версий

Ключ

  • Эта строка добавлена.
  • Эта строка удалена.
  • Изменено форматирование.

...

  1. Создаем новый ноутбук для информации о приложении, например, с именем appstoreconnect_example.

  2. Первым блоком подключаем все необходимые нам для работы Python библиотеки:

    Блок кода
    languagepy
    import petl as etl # для загрузки и обработки данных
    import pandas as pd # для удобной работы с датой и выгрузки таблицы в postgresql
    
    import datetime as dt # для рассчёта даты
    
    from appstoreconnect import Api # для подключения к App Store Connect API
    import sqlalchemy # для создания подключения к базе данных

  3. Вторым блоком подключаемся к API App Store с помощью Python библиотеки Appstoreconnect. Данные для подключения можно получить, следуя документации Creating API Keys for App Store Connect API:

    Блок кода
    api = Api(key_id, path_to_key_file, issuer_id) # инициализация данных для api

  4. Указываем период дат, за который будут браться отчёты. Будем использовать период с 01.01.2021 по текущую дату. Для этого обратимся к библиотеке Pandas и вызовем ее метод date_range(). В этот метод мы передаем два параметра: start (начальная дата периода), end (конечная дата периода). Их мы определяем с помощью Python библиотеки datetime.

    Блок кода
    languagepy
    dateRange = pd.date_range(start = dt.datetime.today().strftime('%Y-01-01'), 
                              end = dt.datetime.today()) # установка диапазона дат


    На выходе мы получим вот такой объект:


    Его элементы проиндексированы, каждый элемент - это дата, за которую мы будем запрашивать информацию по API.

  5. Создадим фиксированный словарь с кодами стран и их расшифровкой, они понадобятся для дальнейшей работы с таблицей. Если вы хотите получать коды и названия стран динамически (чтобы он всегда был актуален), то можете воспользоваться API REST Countries или другим доступным в Интернете методом.

    Блок кода
    # коды стран
    codes = {
        'AD': 'Andorra',
        'AE': 'United Arab Emirates',
        ...
        'ZW': 'Zimbabwe',
        'ZZ': 'Unknown or unspecified country',
    }

  6. Отчёт формируется путём запроса информации за каждый день. На одну дату - один отчёт. Поэтому мы создадим список, в котором будем хранить первым элементом - названия столбцов, а последующими - информацию по датам.

    Блок кода
    # получение отчётов
    sales=list()
    isFirstRow = True
    for reportDate in dateRange:
        try:
            resp = api.download_sales_and_trends_reports(filters={
                'vendorNumber': '{vendorNumber}', 
                'frequency': 'DAILY', 
                'reportDate': reportDate.strftime('%Y-%m-%d')
            }).partition('\n')

    Где {vendorNumber} - это ваш vendor numberидентификационный номер, который вы можете узнать в своём аккаунте App Store Connect.

    При получении отчёта в переменной resp хранятся названия столбцов вместе со значениями столбцов:


    Для удобной работы с этими данными мы применяем к переменной resp строковый метод partition(). В качестве параметра мы передаем ему символ ‘\n’. В итоге получается кортеж, нулевой элемент которого – это название столбцов, первый - наш разделитель ‘\n’, а второй - собранные данные по дате:


    Поскольку всё это происходит в цикле, то данные правила будут применимы к каждому полученному отчёту.
    Так как мы хотим создать список, первым элементом которого будут названия столбцов, а другими - значения этих столбцов, то для начала нам нужна проверка для первой строки.

    Блок кода
            if isFirstRow:
                sales.append(resp[0]) # resp[0] хранит в себе только названия столбцов
                isFirstRow = False
            sales.extend(resp[2].split('\n')) # resp[2] хранит в себе собранные данные по дате
            print(reportDate)
        except:
            continue


    После добавления названий столбцов, мы ставим переменную isFirstRow в положение False, чтобы названия столбцов не повторялись. Затем, чтобы разделить между собой значения столбцов, мы используем метод split() и передаем ему в качестве параметра символ ‘\n’. И, используя метод extend(), добавляем значения в список sales. По итогу, переменная sales содержит в себе названия столбцов (в качестве нулевого элемента) и значения столбцов (в качестве последующих элементов):

  7. Нужно привести данные в тот вид, с которым может работать библиотека Petl.Для этого мы разделим каждый элемент нашего списка sales по символу ‘\t’ с помощью уже известного метода split(). Поместим эти значения в переменную splitted:

    Блок кода
    splitted = [x.split('\t') for x in sales if x]


    Теперь переменная splitted хранит в себе списки без лишних символов:


    Нулевой элемент этого списка – названия столбцов, а все остальные элементы – значения столбцов.

  8. Теперь библиотека Petl с лёгкостью сформирует из этого списка таблицу. Для более информативного отображения мы добавим в таблицу столбец Country, в который поместим расшифровку кодов стран из столбца Country Code. Воспользуемся методом addfield() библиотеки Petl. Этот метод в качестве параметров принимает переменную, из которой строится таблица (нашем случае это переменная splitted), название нового столбца, и значение, которым будет заполнен столбец. В качестве этого значения можно передать анонимную функцию (лямбда выражение). У нашей функции в качестве переменной x - код страны. Мы будем использовать словарный метод get(), передадим ему переменную x. Функция будет искать в нашем словаре codes ключи из столбца Country Code и возвращать значения по этим ключам. Эти значения мы и запишем в новый столбец Country.

    Блок кода
    tbl = etl.addfield(splitted, 'Country', lambda x: codes.get(x['Country Code'])) # добавление столбец со странами


    Так будет выглядеть сформированная таблица:

  9. Как видно, она не идеальна и хранит в себе столбцы с пустыми значениями, а так же те столбцы, которые не затрагиваются в данном примере. Воспользуемся методом cut(). В качестве параметров передаем ему нашу таблицу, и далее, через запятую в апострофах, мы передаем названия тех столбцов, которые хотим оставить в таблице:

    Блок кода
    languagepy
    tbl = etl.cut(tbl, 'Title', 'Version', 'Units', 'Begin Date', 'Device', 'Country') # отбор нужных столбцов


    На выходе получится такая таблица:

  10. Теперь можно экспортировать нашу таблицу в Excel файл для дальнейшей загрузки на платформу. Для этого воспользуемся методом toxlsx() библиотеки Petl. В качестве параметров передаем методу название Excel файла, флаг write_header=True указывает, что нужно записывать заголовки в таблицу, флаг mode='replace' указывает, что файл будет перезаписываться при повторном запуске кода.

    Блок кода
    tbl.toxlsx('appstoreconnect.xlsx', write_header=True, mode='replace') # экспорт в excel


    Мы получили Excel таблицу, которую можно загружать на платформу:

  11. Помимо экспорта а Excel продемонстрируем подход с сохранением данных в PostgreSQL. Установим подключение к базе данных с помощью метода create_engine() библиотеки Sqlachemy.

    Блок кода
    engine = sqlalchemy.create_engine('postgresql://{user}:{user_password}@{url}:{port}/{database_name}') # подключение к базе данных


    Где {user} - имя пользователя базы данных, {user_password} - пароль, {url} - адрес базы данных, {port} - порт, {database_name} - название базы данных, в которой будет создана таблица.

  12. Далее создадим объект DataFrame библиотеки Pandas из нашей таблицы Petl. Воспользуемся методом DataFrame() и укажем ему, что названия колонок находятся - это tbl[0], а значения - это срез от первого элемента таблицы Petl до последнего tbl[1:].

    Блок кода
    df = pd.DataFrame(columns=tbl[0], data=tbl[1:] # создание DataFrame из petl-таблицы


    Получим таблицу Pandas:

  13. Теперь экспортируем таблицу в базу данных PostgreSQL с помощью метода to_sql() библиотеки Pandas. В параметрах передаем название таблицы, переменную подключения engine, которую определили выше, флаги index=Falseиif_exists='replace, и словарь с типами данных для столбцов. Флаг index=Falseговорит, что не нужно создавать столбец с индексами. Флаг if_exists='replace' указывает, что таблицу нужно перезаписать, если она уже существует. В словаре dtype мы указываем название столбца в качестве ключа, а в качестве значения указывается тип данных библиотеки Sqlalchemy и его длина. Типы данных можно посмотреть тут.

    Например, для столбца ‘Title’ мы укажем тип данных VARCHAR с длинной 25. Указывается такая длина, т.к. в нашем примере длина названия приложения не будет больше 25-ти символов.

    Блок кода
    languagepy
    # экспорт в базу данных
    df.to_sql('mobileappdownload', engine, index=False, if_exists='replace', dtype={
        'Title': sqlalchemy.types.VARCHAR(25),
        'Version': sqlalchemy.types.VARCHAR(5),
        'Units': sqlalchemy.types.Integer(),
        'Begin Date': sqlalchemy.types.Date(),
        'Category': sqlalchemy.types.VARCHAR(20),
        'Device' : sqlalchemy.types.VARCHAR(10),
        'Countries': sqlalchemy.types.VARCHAR(30)
    })  a

...