Pull to refresh

Получаем статистику расходов по MCC: Тинькофф и Рокетбанк

Reading time6 min
Views19K


Введение


MCC (Merchant Category Code) — код категории продавца, используемый при операциях с банковскими картами. По этому коду банк определяет, товар какой категории приобрёл клиент. От него зависит, начислят вам кэшбэк, комиссию или отменят льготный период.


В век, когда компании зарабатывают на данных, собираемых с пользователей, грех не воспользоваться обратным ходом: использовать данные о себе, собранные компаниями, чтобы, если не заработать на этом, то хотя бы сэкономить.


Зная, какие суммы вы тратите по каждому MCC-коду, можно рассчитать, какая банковская карта принесёт большую выгоду. Поэтому, если вы достаточное время пользовались картой Тинькофф или Рокетбанк, эта статья вам пригодится, чтобы получить статистику трат по каждому MCC.


Тинькофф


Личный кабинет Тинькофф Банка показывает MCC операции при клике по ней.



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


UPD: Как заметил Smasher, личный кабинет предоставляет возможность выгрузить все операции в формате CSV или Excel. Так что под спойлером описание того, как это делал я, не зная об этом.



Going the hard way

Для этого потребуются инструменты разработки браузера, а конкретно — анализ сетевой активности (вкладка Network в Google Chrome). Если включить анализатор и после этого попросить личный кабинет отобразить операции «За всё время», то мы быстро найдём желаемый запрос.



Можно заметить, что сервер действительно отдал данные за всё время, а в JSON-ответе присутствуют искомые MCC.



Для удобства обработки данных сымитируем запрос на Python. Я использую Jupyter Notebook.



Отправим POST-запрос на URL https://api.tinkoff.ru/v1/grouped_requests с идентичными параметрами sessionid и _methods и данными requestsData.


import requests

session_id = "b785Q2R5US2AZo2p5JoCtNQNkbmYsJbl.ds-api02"
methods = "operations" # нас интересует получение только операций, payments не нужны
params = {'sessionid': session_id, '_methods': methods}

# не мудрствуя лукаво просто скопируем requestsData из запроса
requests_data = '[{"key":0,"operation":"operations","params":{"wuid":"28a44beaeee7460b94dbdd0aa0dc935a","account":"5059373083","start":1136062800000,"end":1529269199999}}]'
data = {'requestsData': requests_data}

response = requests.post('https://api.tinkoff.ru/v1/grouped_requests', params=params, data=data)

Если мы всё правильно сделали, то ввод response.text в консоли выведет тело ответа. Осталось разобрать эти данные и сохранить нужные нам фрагменты.


import csv

operations = []

payload = response.json()['payload']
for key in payload:
    feed = payload[key]['payload']
    for operation in feed:
        mcc = operation['mcc']

        # MCC со значениями < 100 используются банком для операций не связанных с покупками
        if (mcc > 100):

            # если наименование магазина не указано, возьмём описание операции
            if 'merchant' in operation:
                merchant_name = operation['merchant']['name']
            else:
                merchant_name = operation['description']

            # в accountAmount отображается стоимость покупки в «родной» валюте
            cost = operation['accountAmount']['value']                
            operations.append((mcc, cost, merchant_name))
            print(mcc, cost, merchant_name)

# выведем всё в csv
output = open("tinkoff.csv",'w')
wr = csv.writer(output)

for item in operations:
    wr.writerow(item)

На выходе получим таблицу из MCC-кодов, стоимостей покупок и наименований магазинов.


Рокетбанк


Рокетбанк показывает MCC операции в квитанции. Поэтому нам потребуется собрать ссылки на квитанции всех операций.



С Рокетбанком чуть сложнее, потому что доступ в личный кабинет осуществляется только через мобильное приложение. Я расскажу только о том, что заработало у меня, и только про Android. Установим на компьютер анализатор Charles и пропустим трафик с телефона через него.


Для этого телефон и компьютер должны быть подключены к одной сети. Потребуется узнать IP компьютера в локальной сети. Например, с помощью ifconfig.


Далее настроим телефон для работы через прокси-сервер Charles. В Android 7.0 это делается в настройках Wi-Fi при длинном нажатии по подключенной сети. Укажем IP компьютера и порт 8888, по умолчанию используемый Charles.



Само собой разумеется, что приложение Рокетбанка использует TLS при взаимодействии с сервером и просто так прослушать трафик мы не сможем. Charles поддерживает перехват трафика с подменой TLS-сертификата, то есть реализует MITM-атаку. Однако для этого устройство должно доверять корневому сертификату Charles.


Корневой сертификат Charles устанавливается при переходе по ссылке https://chls.pro/ssl с мобильного устройства при включённом проксировании. Кроме того, нужно добавить rocketbank.ru в список проксируемых хостов в Proxy -> SSL Proxying Settings.



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


Сперва достанем пакет приложения с телефона. Это можно сделать с помощью Android Debug Bridge или приложения Apk Extractor. Первый способ у меня на Android 7.0 не сработал, а второй с задачей справился.


Забираем пакет на компьютер и декомпилируем с помощью apktool.


apktool d rocket.apk 

Необходимо добавить файл с конфигурацией сетевой безопасности по пути res/xml/network_security_config.xml. Подробнее про формат файла конфигурации можно почитать здесь, нам же хватит следующей настройки:


<network-security-config> 
  <base-config> 
    <trust-anchors> 
      <!-- Always trust user added CAs -->
      <certificates src="user" /> 
    </trust-anchors> 
  </base-config> 
</network-security-config> 

На этот файл конфигурации нужно указать в манифесте приложения (AndroidManifest.xml в корне), добавив параметр android:networkSecurityConfig в тег application.


<application android:networkSecurityConfig="@xml/network_security_config" android:allowBackup="false" ...>...</application>

Теперь скомпилируем.


apktool b rocket

Осталось подписать приложение, так как неподписанные приложения не устанавливаются. Используем для этого программу для подписи со встроенным тестовым сертификатом.


java -jar sign.jar rocket.apk

Удалите оригинальное приложение Рокетбанка с телефона, скопируйте изменённый пакет на телефон и установите (например, через приложение «Файлы»).


Теперь перехват трафика в Charles должен работать. Откройте приложение Рокетбанка, авторизуйтесь и смотрите в Charles. Вот она, наша ссылка на квитанцию.



Снова вернёмся к Python и сымитируем этот GET-запрос, только не будем мелочиться и попросим сервер отдать нам данные обо всех операциях. Ну или хотя бы о первых 999999.


token = 'c8ccb54b-09e3-4608-a5b4-7914a92c21f3206582'
params = {'token': token, 'page': 1, 'per_page': 999999}

Опытным путём выяснено, что сервер доверяет сессии только в том случае, если вместе с токеном отправлены корректные x-device-id, x-time и x-sig. Нам не жалко, ведь ничего придумывать и считать не придётся, просто скопируем.


x_device_id = 'ANDROID_C6FBB57CD433E756_899EE771-4AC5-46ED-44A1-656CE47A417B'
x_time = '1529194008'
x_sig = 'c486365013ddebe8b7f4599afbf73d26'
headers = {'x-device-id': x_device_id, 'x-time': x_time, 'x-sig': x_sig}

response = requests.get('https://rocketbank.ru/api/v5/operations/sexy_feed', params=params, headers=headers)

Для выдёргивания MCC из квитанции будет достаточно регулярки. Пробегаемся по операциям, читаем квитанцию, прогоняем её через регулярку и всё что надо у нас в кармане.


import re

regex = re.compile('MCC:</dt><.+?>(\d+)</dd>')

operations = []
feed = response.json()['feed']

for item in feed:

    if item[0] == 'operation':
        operation = item[1]
        merchant_name = operation['merchant']['name']
        receipt_url = operation['receipt_url']
        cost = operation['money']['amount']

        # считаем только расходы
        if cost < 0:
            receipt = requests.get(receipt_url)
            match = regex.search(receipt.text)

            if match is not None:
                mcc = match[1]
                operations.append((mcc, -cost, merchant_name))
                print(mcc, -cost, merchant_name)
            else:
                # если MCC не найден, то запишем вместо него название магазина,
                # так как оплата услуг проходит без указания MCC
                operations.append((merchant_name, -cost))
                print(merchant_name, -cost)

output = open("rocket.csv",'w')
wr = csv.writer(output)

for item in operations:
    wr.writerow(item)

Пожалуй, можно удалить изменённое приложение и установить обратно оригинальное.


Итого


Объединив данные от двух банков, сгруппировав операции по MCC с помощью сводной таблицы (Pivot Table), вручную почистив данные от переводов и снятия наличных и местами сгруппировав в похожие категории, я получил следующую картину:



Теперь, воспользовавшись сервисом вроде mcc-codes.ru, можно подобрать карты с повышенным кэшбэком на наиболее затратные категории. И, соотнеся величину возможного кэшбэка со стоимостью годового обслуживания, определить, целесообразно ли оформлять конкретную карту.


Какая от этого выгода? При моих тратах и правильном подборе карт удастся сэкономить от 10 тысяч рублей в год. Стоит ли это того? Решать вам :)

Tags:
Hubs:
Total votes 20: ↑19 and ↓1+18
Comments18

Articles