356 lines
23 KiB
Markdown
356 lines
23 KiB
Markdown
# Импорт банковских выписок за последний год
|
||
|
||
**Создано:** 2026-06-23
|
||
**Цель:** Получить все транзакции за последний год (середина 2025 — июнь 2026) в Budget App, автоматизируя импорт банковских выписок как можно полнее.
|
||
|
||
## Проблема
|
||
|
||
В `Budget.xlsx` данные заканчиваются в **середине 2025** (май-июнь 2025, в зависимости от счёта). Последние ~12 месяцев транзакций не внесены в Excel. Вручную вспомнить каждую трату за год — нереалистично.
|
||
|
||
## Существующий инструмент: budget-bank-statement-converter
|
||
|
||
**Путь:** `~/Developer/budget-bank-statement-converter/`
|
||
**Язык:** Swift (macOS command-line tool)
|
||
**Формат вывода:** CSV с колонками `[дата, сумма, дебет, кредит, категория, комментарий, курс]` — совпадает с форматом Excel.
|
||
|
||
### Поддерживаемые банки
|
||
|
||
| Банк | Формат входа | Конфиг | Статус |
|
||
|------|-------------|--------|--------|
|
||
| Demir | CSV (из PDF → Adobe Extract → CSV) | `demir-config.json` | ✅ Работает |
|
||
| Сбер | CSV (выгрузка из СберБизнес) | `sber-config.json` | ✅ Работает |
|
||
| Тинькофф | CSV (выгрузка из Тинькофф) | `tinkoff-config.json` | ✅ Работает |
|
||
| ВТБ | CSV (из PDF → Adobe Extract → CSV) | `vtb-config.json` | ✅ Работает |
|
||
| Альфа | — | — | ❌ `fatalError("Alfa not implemented")` |
|
||
|
||
### Как работает
|
||
|
||
1. **PDF → CSV**: использует Adobe PDF Extract API (`pdfservices-api-credentials.json`) — загружает PDF, получает ZIP с CSV-таблицами.
|
||
2. **CSV → формат App**: разбирает CSV, маппит категории через regex-конфиг, нормализует double-entry (дебет/кредит/конверсии).
|
||
3. Если нужно — автоматически конкатенирует `fileoutpart0001.csv`… файлы.
|
||
4. Использует OpenAI GPT-3.5-turbo для AI-категоризации (закомментировано, `aiMaxTokens = 80`).
|
||
|
||
### Что нужно для использования
|
||
|
||
- Xcode (для сборки Swift-проекта)
|
||
- `OPENAI_API_KEY` в env (не обязательно, выключено)
|
||
- `pdfservices-api-credentials.json` для Adobe Extract
|
||
- JSON config для каждого банка: `Сбер config`, `Tinkoff config`, `Demir config`, `VTB config`
|
||
|
||
## План импорта
|
||
|
||
### Шаг 1: Получить выписки из банков
|
||
|
||
**Что нужно выгрузить за июнь 2025 — июнь 2026:**
|
||
|
||
| Счёт | Банк | Как получить выписку |
|
||
|------|------|---------------------|
|
||
| Нал RUB | Наличные | Ручной ввод (см. ниже про наличные) |
|
||
| Нал KGS | Наличные | Ручной ввод |
|
||
| Нал USD | Наличные | Ручной ввод |
|
||
| Нал KZT | Наличные | Ручной ввод |
|
||
| Demir ИП | Demir | CSV (интернет-банк/моб. приложение) |
|
||
| Demir ИП USD | Demir | CSV (интернет-банк/моб. приложение) |
|
||
| Demir KGS | Demir | CSV (интернет-банк/моб. приложение) |
|
||
| Demir USD | Demir | CSV (интернет-банк/моб. приложение) |
|
||
| Тинькофф Black | Тинькофф | CSV (выгрузка из Тинькофф) |
|
||
| Тинькофф Кредитка | Тинькофф | CSV (выгрузка из Тинькофф) |
|
||
| Сбер | Сбер | CSV (СберБизнес / PDF) |
|
||
| Сбер Кредитка | Сбер | CSV (СберБизнес / PDF) |
|
||
| Альфа | Альфа | CSV — но конвертер Альфу не поддерживает |
|
||
| Альфа Кредитка | Альфа | — |
|
||
| ВТБ | ВТБ | PDF → Adobe Extract → CSV |
|
||
| ВТБ Кредитка | ВТБ | PDF → Adobe Extract → CSV |
|
||
|
||
### Шаг 2: Конвертировать выписки в CSV формата App
|
||
|
||
Запуск для каждого банка:
|
||
```bash
|
||
./budget-bank-statement-converter --bank <bank> --account <account> <input.csv>
|
||
```
|
||
|
||
Выход: `_processed.csv` с колонками `дата, сумма, дебет, кредит, категория, комментарий, курс`.
|
||
|
||
### Шаг 3: Написать Python импортёр CSV → Budget App DB
|
||
|
||
Существующий `xlsx_import.py` читает из Excel. Нужен новый: `csv_bank_import.py`, который:
|
||
|
||
- Читает CSV в формате App (колонки из `csvHeaders` в `Common.swift`)
|
||
- Привязывает `дебет`/`кредит` к существующим счетам в БД (по имени)
|
||
- Маппит категории из CSV на существующие категории в БД (по имени подкатегории)
|
||
- Игнорирует дубликаты (hash по `date + amount + source + dest + comment`)
|
||
- Поддерживает несколько CSV-файлов за раз (много выписок)
|
||
- Выводит отчёт: сколько добавлено, сколько пропущено (дубликаты), какие категории не найдены
|
||
|
||
### Шаг 4: Импортировать в Budget App
|
||
|
||
```bash
|
||
cd ~/Developer/budget-app
|
||
uv run python src/budget/importers/csv_bank_import.py <output1.csv> <output2.csv> ...
|
||
```
|
||
|
||
### Шаг 5: Дописать недостающее в Swift-конвертере
|
||
|
||
- **AlfaToCSV**: реализовать парсер для Альфа-банка (CSV выгрузка из моб. банка/СберБизнес)
|
||
- **AI-категоризация**: раскомментировать и обновить (GPT-3.5 → DeepSeek/local LLM?)
|
||
|
||
## Наличные расходы — проблема и решение
|
||
|
||
### Проблема
|
||
Наличные траты не трекались последний год. У нас есть конечный остаток налички на руках сейчас, но нет истории по категориям.
|
||
|
||
### Подходы
|
||
|
||
#### A. Снять остаток наличных сейчас → счёт в БД (простой)
|
||
- Посчитать физическую наличку сейчас → записать как `initial_balance` для `Нал RUB`, `Нал KGS`, `Нал USD`, `Нал KZT`.
|
||
- Все траты наличными за год никогда не будут зафиксированы.
|
||
- **Минус:** дыра в данных большого объёма (вероятно значительная часть расходов).
|
||
|
||
#### B. Экстраполяция по историческим трендам (средний)
|
||
- Взять помесячные тренды наличных трат по категориям за 2023–первую половину 2025.
|
||
- Экстраполировать на июнь 2025 — июнь 2026 с учётом сезонности.
|
||
- Создать транзакции-плейсхолдеры с пометкой `import_id = 'cash_estimate'`.
|
||
- **Минус:** неточность, может не отражать реальные изменения.
|
||
|
||
#### C. Ретроспектива через месяц-два + экстраполяция (предпочтительный)
|
||
- **Сейчас:** начать трекать наличные расходы (вручную или через мобильный интерфейс Budget App).
|
||
- **Через 1–2 месяца:** по собранным данным наличных трат вычислить реальные помесячные паттерны.
|
||
- Экстраполировать на пропущенный год с этими паттернами.
|
||
- **Плюс:** база для экстраполяции будет основана на реальных данных, а не на исторических.
|
||
|
||
#### D. None of the above — принять дыру
|
||
- Сделать только безналичный импорт. Наличные начинаем трекать с сегодня.
|
||
- В аналитике отмечать периоды как "без наличных".
|
||
- **Плюс:** не надо ничего выдумывать.
|
||
|
||
### Рекомендация: C+D combined
|
||
1. Трекать наличку вручную через UI Budget App начиная с сегодня.
|
||
2. Через 2 месяца посчитать реальные тренды и решить, стоит ли экстраполировать на прошлый год.
|
||
3. Если нет — просто принять дыру и жить с хорошей аналитикой начиная с 2026-06.
|
||
|
||
## Что уже реализовано в Budget App для импорта
|
||
|
||
- ✅ `xlsx_import.py` — полный импорт из Budget.xlsx (34k строк)
|
||
- ✅ Все счета, категории, курсы, транзакции — в БД
|
||
- ✅ Идемпотентный UPSERT для счетов и курсов
|
||
- ✅ Транзакции добавляются обычным insert (без import_hash после фикса)
|
||
|
||
## Реализованный скрипт: bank_scraper
|
||
|
||
**Путь:** `~/Developer/budget-app/scripts/bank_scraper/`
|
||
|
||
Структура:
|
||
```
|
||
scripts/bank_scraper/
|
||
├── __init__.py
|
||
├── .gitignore # config.yaml + data/imports/ не коммитятся
|
||
├── config.example.yaml # шаблон для копирования в config.yaml
|
||
├── base_driver.py # base class BankDriver + load_config()
|
||
├── orchestrator.py # entry point (н.п.)
|
||
└── drivers/
|
||
└── demir.py # Demir IB драйвер (н.п.)
|
||
```
|
||
|
||
**Статус:** ✅ base + Demir driver написаны, Playwright установлен. **НО — Demir требует QR-логин через мобильное приложение**, не логин/пароль на сайте.
|
||
|
||
## Реальность Demir IB
|
||
|
||
Сайт `93.171.215.109` (и `apps.demirbank.kg/ib/`) — **Flutter web SPA** с QR-аутентификацией. Нет формы логина с паролем — нужно сканировать QR мобильным приложением Demir.
|
||
|
||
**Варианты решения:**
|
||
|
||
### A. Продолжить с Playwright + session persistence
|
||
- Один раз залогиниться руками (QR → моб. приложение)
|
||
- Сохранить session cookies/storage в persistent context
|
||
- Дальше переиспользовать сессию для выгрузок (пока не протухнет)
|
||
- **Плюс:** минимум кода
|
||
- **Минус:** сессия рано или поздно протухнет, нужен ручной ре-логин
|
||
|
||
### B. Appium / ADB — эмуляция мобильного приложения
|
||
- Демонстратор Android/iOS эмулятора с мобильным приложением Demir
|
||
- Appium для UI automation внутри приложения
|
||
- **Плюс:** полный контроль
|
||
- **Минус:** сложно, накладно
|
||
|
||
### C. Заменить Demir на первый банк с логином/паролем
|
||
- Тинькофф имеет API для разработчиков (OAuth)
|
||
- Сбер — есть API SberBusinessAPI (хотя для юрлиц)
|
||
- Можно начать с Тинькофф: Tinkoff API → выписка без браузера
|
||
- **Плюс:** самый простой tech-wise
|
||
- **Минус:** Demir пока под вопросом
|
||
|
||
### D. Парсить CSV выписки, которые уже есть в mobile/email
|
||
- Возможно Demir присылает выписки на email
|
||
- Или можно скачать через мобильное приложение → экспорт → AirDrop/email себе
|
||
- Это полу-ручной подход (но быстрее чем QR scraping)
|
||
|
||
## Решение
|
||
|
||
**Рекомендация: A + D**
|
||
1. Самый ценный банк — **Тинькофф** (есть API) — начинаем с него
|
||
2. Demir — разово выгрузить через мобильное приложение (Export CSV/email)
|
||
3. Если сессия Demir долго живёт — Playwright persistent context отработает
|
||
|
||
### Новый порядок разработки
|
||
|
||
1. ✅ Demir driver (написан, но упирается в QR)
|
||
2. **Tinkoff API driver** — следующий приоритет (без браузера, REST API)
|
||
3. **Сбер / ВТБ / Альфа** — Playwright или Tinkoff-style API
|
||
4. **Parse Demir CSV** — Python-версия DemirToCSV для уже скачанных файлов
|
||
|
||
## Файл вывода Swift-конвертера
|
||
|
||
```
|
||
csvHeaders = ["дата", "сумма", "дебет", "кредит", "категория", "комментарий", "курс"]
|
||
```
|
||
|
||
- `дата` — `dd.MM.yyyy HH:mm` (формат EUR)
|
||
- `сумма` — строка с суммой (±знак)
|
||
- `дебет` — имя счёта-источника (пусто = доход извне)
|
||
- `кредит` — имя счёта-получателя (пусто = расход вовне)
|
||
- `категория` — имя подкатегории
|
||
- `комментарий` — очищенный текст
|
||
- `курс` — кросс-курс при внутреннем переводе между валютами
|
||
|
||
## Автоматизация выгрузки выписок из банков
|
||
|
||
### 1. Browser automation libraries (CV-driven)
|
||
|
||
| Библиотека | Язык | Браузеры | CV | 2FA/SMS |
|
||
|-----------|------|----------|----|---------|
|
||
| **Playwright** (MS) | Python, JS, Java, .NET ⭐ | Chromium, Firefox, WebKit | Есть (locator screenshots) | `page.wait_for_selector` на поле ввода кода |
|
||
| **Puppeteer** (Google) | JS (Python через pyppeteer) | Chromium | Есть | — |
|
||
| **Selenium** | Python, Java, JS и др. | Все major | Через сторонние утилиты | — |
|
||
|
||
**Рекомендация: Playwright Python** — де-факто стандарт в 2025, cross-browser, async, видит элементы даже в SPA, встроенные ожидания. Подходит и для РФ-банков (Сбер, Тинькофф, Альфа-клик — все на SPA).
|
||
|
||
### 2. Готовые решения на GitHub
|
||
|
||
**AploBankParsers** ([github.com/Zaurrex1/AploBankParsers](https://github.com/Zaurrex1/AploBankParsers)):
|
||
- Парсер выписок **СберБизнес** (production-ready) — читает xlsx/сsv из уже выгруженного файла
|
||
- Заглушки для Альфа, ВТБ, Тинькофф
|
||
- Это парсер **уже скачанных файлов**, не скрапер
|
||
|
||
**bank_scrapers** ([github.com/eebette/bank_scrapers](https://github.com/eebette/bank_scrapers)):
|
||
- Playwright-based для scraping bank websites
|
||
- Generic, не специфичен под РФ-банки
|
||
|
||
**Sber API** — официальный REST API Сбера:
|
||
- `developers.sber.ru/docs/ru/sber-api/specifications/statement/transactions`
|
||
- Получение выписки по счёту за 5 лет
|
||
- **Требует** корпоративного доступа (SberBusinessAPI / ДБО), не подойдёт для личного СберБанк
|
||
|
||
**Готового решения "под ключ" для РФ-банков** (Playwright → bank login → 2FA → CSV выписка) **нет** в открытом доступе. Каждый банк — свой уникальный UI и flow. Придётся писать самим.
|
||
|
||
### 3. Архитектура скрипта
|
||
|
||
```
|
||
┌─────────────────────────────────┐
|
||
│ Telegram Bot (Hermes/кит) │ ← запрашивает SMS-код
|
||
├─────────────────────────────────┤
|
||
│ Orchestrator (Python) │ ← запускает по крону / кнопке
|
||
│ ┌─────────────────────────┐ │
|
||
│ │ Playwright browser │ │ ← drives bank login page
|
||
│ │ - headless=false │ │ (visible для отладки)
|
||
│ │ - persistent context │ │ (сессия не слетает)
|
||
│ └─────────────────────────┘ │
|
||
│ ┌─────────────────────────┐ │
|
||
│ │ Bank drivers: │ │
|
||
│ │ - tinkoff.py │ │
|
||
│ │ - sber.py │ │
|
||
│ │ - alfa.py │ │
|
||
│ │ - demir.py │ │
|
||
│ │ - vtb.py │ │
|
||
│ └─────────────────────────┘ │
|
||
│ ┌─────────────────────────┐ │
|
||
│ │ Output: CSV в формате │ │
|
||
│ │ budget-bank-statement- │ │
|
||
│ │ converter │ │
|
||
│ └─────────────────────────┘ │
|
||
└─────────────────────────────────┘
|
||
```
|
||
|
||
### 4. Flow для каждого банка
|
||
|
||
```
|
||
1. Запустить headless Playwright (или visible=False для отладки)
|
||
2. Открыть страницу логина банка
|
||
3. Ввести credentials (из конфига, НЕ скрипта)
|
||
4. Если запрошен SMS-код:
|
||
→ отправить в Telegram: "Код из смс для {bank}:"
|
||
→ ждать ответа (polling/async)
|
||
→ ввести полученный код
|
||
5. Дождаться загрузки дашборда
|
||
6. Перейти на страницу выписок/истории
|
||
7. Указать период: 2025-06-01 — 2026-06-23
|
||
8. Скачать CSV/Excel
|
||
9. Сохранить в ~/Developer/budget-app/data/imports/{bank}/{date}.csv
|
||
10. Конвертировать через budget-bank-statement-converter (или Python-версию)
|
||
11. Импортировать в БД
|
||
12. Закрыть браузер
|
||
```
|
||
|
||
### 5. Обработка SMS-кодов (Telegram)
|
||
|
||
Скрипт не должен хранить сессию банка, каждый запуск — новая авторизация.
|
||
|
||
**Варианты:**
|
||
1. **Telegram Bot (inline keyboard)**: скрипт ждёт сообщение, когда нужен код — присылает кнопку "Отправить код для {bank}", пользователь вводит → скрипт вставляет
|
||
2. **Hermes-агент**: крон-джоб спрашивает в Telegram нужный код, ждёт ответа через webhook
|
||
3. **Простой stdin**: скрипт пишет "Введите код для Тинькофф:" и ждёт ввод (если запуск из терминала)
|
||
|
||
**Рекомендация: вариант 1** — TG bot минимальная зависимость, полный контроль.
|
||
|
||
Для реализации: существующий Hermes/Zulip может служить relay. Или простой скрипт на Python + python-telegram-bot с `await incoming_message`.
|
||
|
||
### 6. Чувствительность данных — ограничения
|
||
|
||
Скрипт будет:
|
||
- Знать **логины/пароли** банков (хранятся в локальном конфиге, НЕ в коде)
|
||
- Открывать **браузер на машине Алекса** (никаких VPN/прокси)
|
||
- Передавать только SMS-коды через TG — пароли не передаются
|
||
- Работать **локально**, без LLM/агентов в browser automation
|
||
|
||
Код пишем так, чтобы ни одна строка credentials не была в скрипте:
|
||
```python
|
||
# config.yaml (chmod 600)
|
||
banks:
|
||
tinkoff:
|
||
login: "7999..."
|
||
password: "..."
|
||
phone: "7999..."
|
||
sber:
|
||
login: "..."
|
||
password: "..."
|
||
```
|
||
|
||
### 7. Альтернатива: API банков (без browser)
|
||
|
||
| Банк | REST API для личных счетов | Комментарий |
|
||
|------|---------------------------|-------------|
|
||
| Тинькофф | Есть (Tinkoff API для разработчиков) | Требует регистрации приложения, OAuth |
|
||
| Сбер | Sber API для юрлиц, нет для личных | Не подходит |
|
||
| Альфа | Альфа-Бизнес API (юрлица) | Не подходит |
|
||
| Demir | Нет публичного API | — |
|
||
| ВТБ | Нет публичного API | — |
|
||
|
||
Тинькофф — единственный из списка, у кого есть адекватный API для физлиц (Tinkoff API / Tinkoff Invest API). Можно получить выписку через API, без browser. Остальные — только SPA scraping.
|
||
|
||
**Код:** 10 swift-файлов, ~2 400 строк.
|
||
|
||
**Что хорошо:**
|
||
- Хорошая архитектура: каждый банк = отдельный struct с чётким интерфейсом
|
||
- Конфиги вынесены из кода (JSON)
|
||
- Regex-маппинг категорий гибкий
|
||
- Умеет объединять multi-part CSV и извлекать из PDF через Adobe API
|
||
- Формат вывода совпадает со структурой Excel/Budget App
|
||
|
||
**Чего не хватает:**
|
||
- Парсер Альфа-банка (только заглушка)
|
||
- AI-категоризация закомментирована (GPT-3.5, устарела)
|
||
- Нет интеграции с Budget App (только → CSV, не → БД)
|
||
- Нет обработки для Demir ИП USD / Demir USD / Demir KGS отдельно (DemirToCSV один конфиг на все)
|
||
- PDF-парсер привязан к Adobe PDF Extract API (платный сервис, credentials нужны)
|
||
- Нет обработки для Сбер Кредитка как отдельного счёта (SberToCSV один конфиг)
|
||
- Нет автоматического определения новых форматов CSV от банков
|