Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Ozon Parser

Парсер товаров Ozon через внутренний JSON API (mweb_client). Не использует браузер — запросы делаются напрямую через curl_cffi с имитацией TLS-отпечатка Chrome. Результат сохраняется в XLSX.

Как это работает

  1. Поисковый запрос отправляется на entrypoint-api.bx/page/json/v2 с мобильным User-Agent
  2. API возвращает JSON с товарами в поле widgetStates.tileGrid2-*
  3. Пагинация строится через поле nextPage или shared.catalog.totalPages
  4. Результат записывается в Excel-файл

Требования

  • Python 3.11+
  • Аккаунт Ozon (нужны куки для авторизации запросов)

Установка

git clone <repo>
cd OZON_PARSER

python -m venv venv
source venv/bin/activate        # macOS / Linux
# venv\Scripts\activate         # Windows

pip install -r requirements.txt

Настройка куки

Парсер подставляет куки в запросы как у обычного браузера. Без куки авторизованной сессии Ozon часто отвечает 403 или отдаёт пустую выдачу.

Файл с куки: ozon_cookies.json в корне проекта (рядом с requirements.txt). Путь зашит в src/config.pyConstants.COOKIES_FILE.

Как получить куки (Chrome + EditThisCookie)

  1. Установи расширение EditThisCookie (Chrome / браузеры на Chromium).
  2. Открой https://www.ozon.ru, при необходимости прими cookies-баннеры на сайте.
  3. Войди в аккаунт Ozon (телефон / почта — как обычно в магазине).
  4. Убедись, что страница открыта на домене ozon.ru.
  5. Нажми иконку EditThisCookie на панели расширений.
  6. Нажми «Экспорт» (иконка стрелки вниз) — JSON попадёт в буфер обмена.
  7. Создай в корне проекта файл ozon_cookies.json и вставь содержимое буфера (валидный JSON, UTF-8).
  8. Сохрани файл. В логе при запуске должно быть: Загружено куки: N шт. при N > 0.
OZON_PARSER/
├── ozon_cookies.json   ← сюда
├── requirements.txt
└── src/

Формат файла

Парсер читает массив объектов, как отдаёт EditThisCookie. Нужны поля name и value у каждого элемента:

[
  { "name": "session_id", "value": "...", "domain": ".ozon.ru" },
  { "name": "...", "value": "..." }
]

Экспорт одной строкой вида a=b; c=d не подходит — нужен JSON-массив.

Если не работает

  • Переэкспортируй куки после повторного входа на ozon.ru.
  • Не коммить ozon_cookies.json в git (файл в .gitignore).
  • Куки со временем протухают; при пустой выдаче или 403 снова сделай экспорт.

Если после обновления куки всё ещё пусто — проверь OZON_APP_VERSION в config.py (см. раздел ниже).

Запуск

source venv/bin/activate

# Базовый запуск — 10 товаров (страницы качаются, пока не наберётся лимит)
python src/main.py "название товара"

# Указать количество товаров (страницы подбираются автоматически)
python src/main.py "тенет т4" --limit 100

# Жёсткий лимит страниц (например, не больше 5 запросов к API)
python src/main.py "тенет т7" --limit 40 --pages 5

# Указать путь к файлу результатов
python src/main.py "тенет т7" --output results/тенет_т7_new.xlsx

Аргументы

Аргумент По умолчанию Описание
query Поисковый запрос (обязательный)
--limit N 10 Максимальное количество товаров в результате
--pages N нет Потолок по страницам; без флага страницы запрашиваются, пока не наберётся --limit или не кончится выдача
--output FILE results/{query}_{YYYY-MM-DD}.xlsx Путь для сохранения XLSX

Пример вывода

INFO  | Загружено куки: 10 шт.
INFO  | Страница 1: 8 товаров
DEBUG | totalPages=3, currentPage=1
DEBUG | next_path: '/category/avtomobili-39803/?...&page=2'
INFO  | Страница 2: 8 товаров
INFO  | Страница 3: 8 товаров
INFO  | Статистика парсинга:
         Всего товаров: 20
         С ценами: 20
         Запрос: "тенет т4"
INFO  | Результаты сохранены: results/тенет т4_2026-04-03.xlsx

Структура XLSX

Название Цена Ссылка Дата сбора
TENET T4 Автомобиль... 2 082 240 ₽ https://www.ozon.ru/product/... 2026-04-03 11:47:17

Тесты

В requirements.txt указан pytest — ставится вместе с остальными зависимостями. Тесты не ходят в сеть: API и search_products подменяются моками, куки для прогона не нужны.

Запуск из корня репозитория (виртуальное окружение должно быть активировано):

python -m pytest tests/ -v

Конфигурация: pytest.ini (pythonpath = src, каталог tests/). Общая настройка путей дублируется в tests/conftest.py (как в учебном проекте с парсером PEP).

Файл Содержание
tests/test_config.py класс Constants, URL, файл куки, лимит страниц
tests/test_main.py CLI (parse_args), вызов main с моком парсера
tests/test_utils.py load_cookies, extract_items, parse_item, next_page_url
tests/test_middlewares.py fetch_pages при подмене api_request
tests/test_output.py запись XLSX по умолчанию и отсутствие файла при пустой выдаче
tests/test_files.py состав src/, структура тестов, ключевые строки в requirements.txt
tests/fixture_data/api_samples.py минимальные JSON-подобные ответы API для фикстур

Один тестовый прогон подбирает логику парсинга и CLI; регрессии после правок проще ловить таким набором, чем только ручным запуском.

Настройка

Все параметры находятся в src/config.py.

Прокси

Если нужно использовать прокси (например, при блокировке IP):

# src/config.py
PROXY = {
    'server': 'http://host:port',
    'username': 'user',       # опционально
    'password': 'pass',       # опционально
}

Поддерживаются HTTP/HTTPS прокси. Для обхода защиты Ozon рекомендуются резидентные прокси (Bright Data, Smartproxy, Webshare) — дата-центровые и VPN блокируются.

Версия приложения

OZON_APP_VERSION в config.py соответствует версии фронтенда Ozon. Если парсер перестанет работать — нужно обновить это значение:

  1. Открой DevTools в Chrome на ozon.ru → Network → Fetch/XHR
  2. Найди запрос к entrypoint-api.bx
  3. Скопируй значение заголовка x-o3-app-version из вкладки Headers
# src/config.py
OZON_APP_VERSION = 'release_2-3-2026_659ea623'  # обновить при поломке

Структура проекта

OZON_PARSER/
├── ozon_cookies.json       # куки из Chrome (не коммитить в git)
├── pytest.ini              # настройки pytest (pythonpath, testpaths)
├── requirements.txt
├── results/                # XLSX с результатами (создаётся автоматически)
├── tests/                  # pytest: conftest, фикстуры, тесты модулей
│   ├── conftest.py
│   ├── fixture_data/
│   └── test_*.py
└── src/
    ├── config.py           # все настройки
    ├── main.py             # точка входа, CLI
    ├── middlewares.py      # OzonParser — API-клиент
    └── utils.py            # парсинг ответа API, загрузка куки

Масштабирование

Текущий проект сохраняет срез выдачи в XLSX — этого достаточно для разовых отчётов. Ниже — направления, если нужны история, поиск по накопленным данным или вызов парсера из ИИ-ассистентов.

Запись результатов в БД

Имеет смысл, если нужны повторные запросы по тем же товарам, динамика цен или интеграция с BI/дашбордами.

  • SQLite — минимальный порог: один файл, без отдельного сервера, удобно для локальной автоматизации и прототипов.
  • PostgreSQL (или MySQL) — когда много записей, конкурентная запись и резервное копирование на уровне СУБД.

Практические шаги при доработке кода:

  1. После search_products (или внутри обхода страниц) брать не только DataFrame, но и список словарей до обрезки по limit, либо итерировать строки датафрейма.
  2. В таблице хранить как минимум: время сбора, поисковый запрос, название, цена (текстом как сейчас или распарсенным числом и валютой), URL товара. Из URL Ozon можно выделить идентификатор товара и использовать его в уникальном ключе или в логике «не дублировать карточку в рамках одного среза».
  3. Для многоразовых цен по одному SKU — отдельная таблица «цена на дату» (товар + timestamp + цена), чтобы не перетирать историю.
  4. В Python обычно берут SQLAlchemy (и при необходимости Alembic для миграций схемы). Пакет pandas уже в проекте — метод DataFrame.to_sql() может ускорить первый черновой вариант без ORM, но для продакшена лучше явная схема и индексы по product_id, collected_at, query.

Слой сохранения лучше отделить от main.py (например, модуль storage.py или сервис, который получает list[dict] от OzonParser).

Обёртка в MCP-сервер для работы с LLM

MCP (Model Context Protocol) позволяет подключать к чатам и агентам инструменты (tools): модель вызывает зарегистрированную функцию с параметрами, сервер выполняет действие и возвращает структурированный ответ.

Идея для этого парсера:

  • Реализовать небольшой процесс MCP server (stdio или HTTP/SSE — в зависимости от клиента: Cursor, Claude Desktop, кастомный агент).
  • Зарегистрировать инструмент, например search_ozon с аргументами query: str, limit: int, опционально max_pages: int.
  • Внутри обработчика создавать OzonParser, вызывать await search_products(...), возвращать LLM JSON (список товаров с полями название / цена / ссылка / дата) вместо или вместе с путём к XLSX.

Так ассистент сможет отвечать на запросы вроде «найди на Ozon … подороже 50 тыс. и дай ссылки», не дублируя логику парсинга в промпте. Важно: куки и лимиты API остаются на стороне сервера; в репозиторий не кладут секреты, доступ к MCP ограничивают так же, как доступ к машине с ozon_cookies.json.

Готовых файлов MCP в этом репозитории нет — блок описывает направление доработки, если понадобится сценарий «парсер как инструмент для LLM».

Ограничения

  • Куки нужно обновлять раз в несколько недель
  • OZON_APP_VERSION может устареть после деплоя Ozon (обычно стабилен несколько недель)
  • Количество товаров ограничено тем, сколько реально есть на Ozon по запросу

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages