Разработка · 6 мин чтения

Парсер Ozon с выгрузкой в Excel: код и разбор ошибок

За полтора года практики я собирал парсер Ozon с выгрузкой в Excel для десятка разных заказчиков - от перекупов, которые сверяют цены конкурентов раз в сутки, до владельцев интернет-магазинов на WooCommerce, которым нужна еженедельная выгрузка ассортимента по нескольким тысячам SKU. Ниже - рабочий код на Python, разбор ошибок, с которыми реально сталкивался (403, капча вместо страницы, пустые ответы из-за клиентского рендеринга), и что делать, чтобы выгрузка не отваливалась уже после третьего запуска.

Что можно вытащить с Ozon и зачем это вообще нужно

Ozon отдаёт на карточке товара куда больше, чем видно глазом: название, цену (обычную и по карте/акции), рейтинг, число отзывов, наличие на складах, характеристики, идентификатор продавца. Из категории или поиска можно выгрузить список SKU целиком - это отправная точка почти любого парсера.

На практике запросы делятся на три группы:

  • мониторинг цен конкурентов - нужен, чтобы репрайсер или менеджер вручную корректировал наценку;
  • сбор отзывов и рейтингов - для анализа спроса перед выводом новой позиции в ассортимент;
  • выгрузка своего же каталога - сверка с прайсом на сайте или в учётной системе.

Один из клиентов держит магазин на WooCommerce и раз в сутки сравнивает свои цены с ценами трёх конкурентов на Ozon - выгрузка в Excel идёт прямо в таблицу, по которой менеджер решает, где скорректировать наценку. Без парсера это отслеживание отнимало у него часа полтора в день.

API Ozon Seller и HTML-парсинг - разные задачи

Seller API у Ozon есть, но он открывает данные только по собственному кабинету продавца - свои заказы, остатки, цены, аналитику. Для конкурентной разведки или сбора чужого каталога он бесполезен: чтобы узнать цену на товар конкурента, доступ только один - разбирать HTML страницы или перехватывать её внутренние JSON-запросы.

Разница между вариантами:

Вариант Что даёт Когда использовать
Seller API Данные своего кабинета: заказы, остатки, цены Автоматизация своего магазина на Ozon
requests + BeautifulSoup Разбор отданного HTML/JSON без браузера Когда нужные поля есть в исходном коде страницы
Playwright/Selenium Полный рендеринг страницы, как в браузере Когда данные подгружаются через JS после загрузки

На практике страница товара Ozon отдаёт большую часть данных сразу в HTML - они зашиты в JSON внутри тега script (маркетплейс использует серверный рендеринг и передаёт состояние приложения прямо в разметке). Поэтому в большинстве случаев хватает requests и BeautifulSoup, без headless-браузера - это быстрее в 5-10 раз и не требует Chromium на сервере. Playwright подключаю, только если нужно долистать бесконечную ленту отзывов или каталог подгружает товары через infinite scroll.

Пишем парсер Ozon с выгрузкой в Excel: рабочий код

Ниже - упрощённая, но рабочая версия того, что использую в проектах: собираем список карточек товаров, вытаскиваем название, цену, рейтинг и число отзывов, пишем результат в Excel через openpyxl.

import re
import json
import time
import random
from openpyxl import Workbook
import requests
from bs4 import BeautifulSoup

HEADERS = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
                  "(KHTML, like Gecko) Chrome/124.0 Safari/537.36",
    "Accept-Language": "ru-RU,ru;q=0.9",
}

def get_product_data(url):
    resp = requests.get(url, headers=HEADERS, timeout=15)
    if resp.status_code != 200:
        raise RuntimeError(f"Ozon ответил {resp.status_code} на {url}")

    soup = BeautifulSoup(resp.text, "html.parser")
    script = soup.find("script", string=re.compile("priceRegular"))
    if not script:
        raise ValueError("Не нашёл JSON с данными — вероятно, отдана капча")

    data = json.loads(script.string)
    return {
        "name": data.get("name"),
        "price": data.get("priceRegular"),
        "rating": data.get("rating"),
        "reviews": data.get("reviewsCount"),
    }

def parse_and_export(urls, out_path="ozon_export.xlsx"):
    wb = Workbook()
    ws = wb.active
    ws.append(["Название", "Цена", "Рейтинг", "Отзывы", "URL"])

    for url in urls:
        try:
            item = get_product_data(url)
            ws.append([item["name"], item["price"], item["rating"], item["reviews"], url])
        except Exception as e:
            ws.append(["ОШИБКА", str(e), "", "", url])
        time.sleep(random.uniform(2, 5))

    wb.save(out_path)

if __name__ == "__main__":
    urls = [
        "https://www.ozon.ru/product/example-1",
        "https://www.ozon.ru/product/example-2",
    ]
    parse_and_export(urls)

Несколько моментов, на которые обращаю внимание:

  • признак данных в script-теге Ozon периодически меняет - поэтому ищу не по фиксированному id, а по содержимому (по полю priceRegular);
  • пауза time.sleep(random.uniform(2, 5)) между запросами - без неё блокировка по IP прилетает уже после 20-30 запросов подряд;
  • ошибки не роняют весь скрипт - каждая проблемная строка попадает в Excel с пометкой «ОШИБКА» и текстом причины, чтобы потом отфильтровать и перезапустить точечно.

Если не хочется собирать это с нуля, у меня в библиотеке готовых скриптов есть шаблон в похожей логике - можно адаптировать под свой список категорий за пару часов вместо пары дней.

Бесплатный материал

🎁 Полезный скрипт в подарок

Подпишитесь на Telegram - пришлю готовый скрипт по этой теме.

Без спама. Отписка в 1 клик.

Разбор типичных ошибок при парсинге Ozon

На проектах чаще всего вижу одни и те же четыре проблемы:

Ошибка Причина Что делать
403 Forbidden сразу на первом запросе Дефолтные заголовки requests слишком похожи на бота Полный набор заголовков как у браузера, ротация User-Agent
429 или пустой ответ через 20-40 запросов Сработал рейт-лимит по IP Пауза 2-5 секунд между запросами, прокси при больших объёмах
KeyError / None вместо цены Ozon обновил разметку, изменилась структура JSON try/except на уровне одной карточки, а не всего скрипта
Вместо HTML пришла капча Слишком частые запросы с одного IP, нет cookies сессии Прокси плюс «разогрев» сессии - сначала главная, потом карточка

Самая частая причина, почему парсер «работал вчера, а сегодня падает» - верстка маркетплейса не статична, разработчики Ozon меняют структуру данных без предупреждения. Я закладываю в код обработку ошибок на уровне каждой карточки отдельно, чтобы одна сломанная страница не обрушила всю выгрузку на тысячу позиций.

Как снизить число блокировок при сборе данных с Ozon

Заголовки и паузы решают базовый уровень защиты, но при объёме от пары тысяч карточек в день без прокси почти не обойтись. Использую резидентные или мобильные прокси, а не дата-центровые - последние Ozon вычисляет по подсетям почти сразу. Переиспользую cookies в рамках одной сессии, ограничиваю число запросов в минуту и добавляю ретраи с экспоненциальной задержкой на 429 и 5xx-ответах.

На одном проекте выгрузка 5000 карточек без прокси падала на 400-500‑й позиции стабильно. Добавил ротацию из пяти резидентных прокси и паузу 3-4 секунды - дошли до 5000 без единой капчи, но прогон занял почти 4 часа вместо 40 минут. Такой компромисс стоит закладывать в оценку сроков сразу, а не обещать клиенту выгрузку каталога за час.

Автоматизация выгрузки: расписание, Telegram и n8n

Разовый прогон скрипта руками нормален для теста, но для регулярного мониторинга нужен планировщик. Варианты, которые использую:

  • Windows Task Scheduler или cron на Linux-сервере - если выгрузка нужна раз в день по расписанию;
  • n8n с нодой запуска команды - забирает готовый xlsx и сразу отправляет его на почту или в облачное хранилище без ручного вмешательства;
  • Telegram-бот на aiogram - присылает файл по команде или по кнопке, удобно, когда за выгрузкой должен приходить не разработчик, а менеджер без доступа к серверу.

Для клиента с магазином на WooCommerce собрал именно такую связку: cron раз в сутки запускал парсер, n8n забирал готовый Excel и складывал в общую папку, а менеджер получал уведомление в Telegram, что файл обновился. Ручной работы у него не осталось вообще, кроме самой корректировки цен по итоговой таблице.

Данные и процессы на автопилоте

Парсинг / Автоматизация

от 20 000 ₽

Подробнее →

Частые вопросы

Не забанит ли Ozon за парсинг каталога?

Блокировка обычно точечная - по IP или сессии, а не по аккаунту, потому что сбор данных идёт без авторизации в личном кабинете. При адекватных паузах и прокси риск минимален, но полностью исключить временную капчу нельзя - это обычная часть работы с любым маркетплейсом, а не признак того, что скрипт написан плохо.

Сколько стоит парсер Ozon под ключ?

Собственные проекты по парсингу и автоматизации на Python у меня стоят от 20 000 ₽ - итоговая цена зависит от количества полей, частоты запуска и того, нужна ли интеграция с Excel, 1С или CRM на выходе. На бирже фриланса и в студиях за похожую задачу просят от 15 000 до 50 000 ₽, но там сильно зависит от того, включена ли доработка после первого запуска в цену или идёт отдельно.

Можно ли парсить Ozon без прокси?

Для 100-300 карточек в день обычно да, если выдерживать паузы и не долбить с одного IP слишком часто. Для тысяч позиций или ежедневного мониторинга без прокси почти гарантированно упрётесь в капчу или временную блокировку уже через 20-40 минут работы.

Как часто можно обновлять выгрузку в Excel?

Для мониторинга цен конкурентов хватает одного прогона в сутки - цены на Ozon не скачут каждый час. Для складских остатков в высокий сезон, перед распродажами или в декабре, интервал стоит сократить до 2-3 раз в день, но тогда нужен более аккуратный график запросов, чтобы не спалить IP раньше времени.

Есть задача?

Обсудим в мессенджере

Расскажите, что нужно сделать — отвечу в течение 4 часов в рабочее время. Первая консультация бесплатно.

Самозанятый Калинкин Н. А. · работаю с физлицами и юрлицами

Продолжая пользование настоящим сайтом Вы выражаете своё согласие на обработку Ваших персональных данных (файлов куки) с использованием Yandex.Metrika.
Понятно