Введение
MCC (Merchant Category Code) — код категории продавца, используемый при операциях с банковскими картами. По этому коду банк определяет, товар какой категории приобрёл клиент. От него зависит, начислят вам кэшбэк, комиссию или отменят льготный период.
В век, когда компании зарабатывают на данных, собираемых с пользователей, грех не воспользоваться обратным ходом: использовать данные о себе, собранные компаниями, чтобы, если не заработать на этом, то хотя бы сэкономить.
Зная, какие суммы вы тратите по каждому MCC-коду, можно рассчитать, какая банковская карта принесёт большую выгоду. Поэтому, если вы достаточное время пользовались картой Тинькофф или Рокетбанк, эта статья вам пригодится, чтобы получить статистику трат по каждому MCC.
Тинькофф
Личный кабинет Тинькофф Банка показывает MCC операции при клике по ней.
Так можно посмотреть с десяток операций, но если нам нужно собрать статистику за всё время использования карты, это дело стоит автоматизировать. Попробуем достать данные в удобном для программной обработки виде.
UPD: Как заметил Smasher, личный кабинет предоставляет возможность выгрузить все операции в формате CSV или Excel. Так что под спойлером описание того, как это делал я, не зная об этом.
Для этого потребуются инструменты разработки браузера, а конкретно — анализ сетевой активности (вкладка 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 тысяч рублей в год. Стоит ли это того? Решать вам :)
Комментарии (14)
Imbecile
18.06.2018 00:04У нас с этим стало проще. Монобанк сразу в приложении даёт всё.
ВыпискаKobalt_x
18.06.2018 06:24+1Такую то выписку даже сбер даёт, тут прикол в том, что по такой выписке нельзя понять что ваша любимая кафешка не попадает в категории кафе и рестораны из-за криво выставленного MCC
Imbecile
18.06.2018 08:56Ну, в обычной ленте выписки видно, к какой категории МСС относится какая трата.
Напримерquestor
18.06.2018 10:55А не в курсе, в сбере вообще можно выписки не через выгрузки в эксель, а через нормальное API запрашивать? Тоже подумываю о том, чтобы автоматизировать кое-что, но как подумаю, что для этого придётся руками файлы грузить — так сразу грусть-печаль и забрасываю.
Kobalt_x
18.06.2018 13:42Ну приложение то явно не xlsки парсит так что думаю способом для полета можно попробовать вытащить
dead_undead
18.06.2018 22:24Рокетбанк тоже так умеет, в каждую категорию можно зайти и увидеть траты по ней.
Smasher
18.06.2018 00:44+1Зачем усложнять с Тинькофф-банком, можно же просто выгрузить все транзакции в csv из личного кабинета.
SDVdk
18.06.2018 00:56+1Мой опыт говорит, что смысла экономить на мелочи нет. Лучше подбирайте удобный банк по комплексу хар-к.
И ты ничего не сделаешь с тем, что бронь у тебя проходит по «Отель», а оплата по «Фастфуд», сидя в дорогущем ресторане со четом на 22+.
rhangelxs
18.06.2018 01:09+1А как же «no free lunch»? Несколько карт с разными категориями кэшбека всегда будут лучше чем одна.
Вот ещё бы кто-нибудь сделал приложение, которое показывало с какой карты выгоднее расплатиться.Ar2r
18.06.2018 09:43а потом все карты добавить в Apple pay и чтоб сам телефон считывал mmc и подставлял нужную карту? =)))
Crusader_12
19.06.2018 05:30а потом все карты добавить в Apple pay
и ту наступает облом не все в мире настолько на огрызках помешаны
ViktorIsVeid
Спасибо за статью. Пользуюсь рокетом, как-нибудь руки дойдут попробовать.
P.S. не думаете, что опасно вот так брать и кидать скриншоты с токенами авторизации и идентификаторами сессии? Отправили запрос вы — отправит и кто-нибудь другой, и может много нехорошего наделать, возможно.
Hellishnoob Автор
Спасибо за спасибо :) Перенесли в «Я пиарюсь», ну да ладно, статья на грани.
Идентификаторы сессии и токены авторизации быстро портятся. Не думаю, что их возможно использовать после инвалидации, по крайней мере я сам этого сделать не могу. Только ID устройства затёр на всякий случай.