Парсер товаров Ozon через внутренний JSON API (mweb_client). Не использует браузер — запросы делаются напрямую через curl_cffi с имитацией TLS-отпечатка Chrome. Результат сохраняется в XLSX.
- Поисковый запрос отправляется на
entrypoint-api.bx/page/json/v2с мобильным User-Agent - API возвращает JSON с товарами в поле
widgetStates.tileGrid2-* - Пагинация строится через поле
nextPageилиshared.catalog.totalPages - Результат записывается в 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.py → Constants.COOKIES_FILE.
- Установи расширение EditThisCookie (Chrome / браузеры на Chromium).
- Открой https://www.ozon.ru, при необходимости прими cookies-баннеры на сайте.
- Войди в аккаунт Ozon (телефон / почта — как обычно в магазине).
- Убедись, что страница открыта на домене ozon.ru.
- Нажми иконку EditThisCookie на панели расширений.
- Нажми «Экспорт» (иконка стрелки вниз) — JSON попадёт в буфер обмена.
- Создай в корне проекта файл
ozon_cookies.jsonи вставь содержимое буфера (валидный JSON, UTF-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
| Название | Цена | Ссылка | Дата сбора |
|---|---|---|---|
| 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. Если парсер перестанет работать — нужно обновить это значение:
- Открой DevTools в Chrome на ozon.ru → Network → Fetch/XHR
- Найди запрос к
entrypoint-api.bx - Скопируй значение заголовка
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) — когда много записей, конкурентная запись и резервное копирование на уровне СУБД.
Практические шаги при доработке кода:
- После
search_products(или внутри обхода страниц) брать не толькоDataFrame, но и список словарей до обрезки поlimit, либо итерировать строки датафрейма. - В таблице хранить как минимум: время сбора, поисковый запрос, название, цена (текстом как сейчас или распарсенным числом и валютой), URL товара. Из URL Ozon можно выделить идентификатор товара и использовать его в уникальном ключе или в логике «не дублировать карточку в рамках одного среза».
- Для многоразовых цен по одному SKU — отдельная таблица «цена на дату» (товар + timestamp + цена), чтобы не перетирать историю.
- В Python обычно берут SQLAlchemy (и при необходимости Alembic для миграций схемы). Пакет
pandasуже в проекте — методDataFrame.to_sql()может ускорить первый черновой вариант без ORM, но для продакшена лучше явная схема и индексы поproduct_id,collected_at,query.
Слой сохранения лучше отделить от main.py (например, модуль storage.py или сервис, который получает list[dict] от OzonParser).
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 по запросу