142 lines
3.9 KiB
Markdown
142 lines
3.9 KiB
Markdown
# Magnit price API
|
||
|
||
Локальный HTTP API и CLI для `magnit.ru`, который:
|
||
|
||
- принимает `store_code` и `query`;
|
||
- ищет товары через backend `POST /webgate/v2/goods/search`;
|
||
- сам обновляет `access token` через `POST /magnit-id/v1/auth/token/refresh`;
|
||
- хранит рабочую сессию в `magnit_session.json`.
|
||
|
||
## Быстрый старт
|
||
|
||
Запуск API:
|
||
|
||
```bash
|
||
python3 magnit_api.py serve --host 127.0.0.1 --port 8080
|
||
```
|
||
|
||
## Docker Compose
|
||
|
||
Сборка и запуск:
|
||
|
||
```bash
|
||
cp .env.example .env
|
||
docker compose up -d --build
|
||
```
|
||
|
||
По умолчанию сервис публикуется только в loopback на `127.0.0.1:18080`.
|
||
|
||
Проверка:
|
||
|
||
```bash
|
||
curl "http://127.0.0.1:18080/health"
|
||
curl "http://127.0.0.1:18080/price?store_code=618224&query=Red%20Bull"
|
||
```
|
||
|
||
Если нужен другой внешний порт:
|
||
|
||
```bash
|
||
MAGNIT_API_PORT=18081 docker compose up -d --build
|
||
```
|
||
|
||
Проверка:
|
||
|
||
```bash
|
||
curl "http://127.0.0.1:18081/price?store_code=618224&query=Red%20Bull"
|
||
```
|
||
|
||
CLI без HTTP-сервера:
|
||
|
||
```bash
|
||
python3 magnit_api.py price --store-code 618224 --query "Red Bull"
|
||
python3 magnit_api.py search --store-code 618224 --query "Red Bull"
|
||
```
|
||
|
||
## Endpoint'ы
|
||
|
||
`GET /health`
|
||
|
||
`GET /session`
|
||
|
||
`POST /session/refresh`
|
||
|
||
`POST /session/bootstrap`
|
||
|
||
```json
|
||
{
|
||
"mg_at": "%7B%22access%22%3A%22...%22%2C%22refresh%22%3A%22...%22%7D",
|
||
"device_id": "761fa244-97f7-4b6e-b93a-8c258f357580",
|
||
"device_tag": "8894ea27-7a01-42f0-8500-20eb63bbc7c9_1"
|
||
}
|
||
```
|
||
|
||
`GET /search?store_code=618224&query=Red%20Bull`
|
||
|
||
`GET /price?store_code=618224&query=Red%20Bull`
|
||
|
||
## Nginx proxy_pass
|
||
|
||
Готовый пример лежит в `nginx/magnit-api.location.conf.example`.
|
||
|
||
Если `nginx` стоит на хосте и `docker compose` публикует API на `127.0.0.1:18080`, используйте:
|
||
|
||
```nginx
|
||
location /magnit-api/ {
|
||
proxy_pass http://127.0.0.1:18080/;
|
||
proxy_http_version 1.1;
|
||
|
||
proxy_set_header Host $host;
|
||
proxy_set_header X-Real-IP $remote_addr;
|
||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||
proxy_set_header X-Forwarded-Proto $scheme;
|
||
proxy_set_header X-Forwarded-Host $host;
|
||
}
|
||
```
|
||
|
||
Тогда внешний запрос будет таким:
|
||
|
||
```bash
|
||
curl "https://your-domain.example/magnit-api/price?store_code=618224&query=Red%20Bull"
|
||
```
|
||
|
||
Если `nginx` контейнерный и находится в одной сети с `magnit-api`, замените upstream на `http://magnit-api:8080/`.
|
||
|
||
## Что хранится в сессии
|
||
|
||
`magnit_session.json` содержит:
|
||
|
||
- `refresh_token`
|
||
- `access_token`
|
||
- `device_id` (`mg_udi`)
|
||
- `device_tag` (`mg_ksid`)
|
||
- служебные заголовки браузера
|
||
|
||
Скрипт сам обновляет `access_token`, когда JWT подходит к истечению.
|
||
|
||
## Как перебутстрапить сессию
|
||
|
||
Если `refresh_token` станет невалидным, откройте `magnit.ru`, где вы уже авторизованы, и в DevTools Console выполните:
|
||
|
||
```js
|
||
copy(JSON.stringify({
|
||
mg_at: decodeURIComponent(document.cookie.split('; ').find(v => v.startsWith('mg_at=')).split('=').slice(1).join('=')),
|
||
device_id: document.cookie.split('; ').find(v => v.startsWith('mg_udi=')).split('=').slice(1).join('='),
|
||
device_tag: document.cookie.split('; ').find(v => v.startsWith('mg_ksid=')).split('=').slice(1).join('=')
|
||
}, null, 2));
|
||
```
|
||
|
||
Потом отправьте это в локальный API:
|
||
|
||
```bash
|
||
curl -X POST "http://127.0.0.1:8080/session/bootstrap" \
|
||
-H "Content-Type: application/json" \
|
||
-d @payload.json
|
||
```
|
||
|
||
Если API запущен через `docker compose`, используйте опубликованный порт, по умолчанию `18080`:
|
||
|
||
```bash
|
||
curl -X POST "http://127.0.0.1:18080/session/bootstrap" \
|
||
-H "Content-Type: application/json" \
|
||
-d @payload.json
|
||
```
|