MacOS_Parsers/Parsing ZARAHOME/src
2025-10-16 10:32:49 +03:00
..
categories-old1.xlsx commit 2025-07-28 16:20:11 +03:00
categories-old2.xlsx ZaraHome рабочий без отправки json, IKEA все работает по отдельности 2025-08-05 13:54:46 +03:00
categories.py commit 2025-07-28 16:20:11 +03:00
categories.xlsx categories update 2025-10-13 11:08:01 +03:00
exclusion_materials.txt ZARAHOME 2.0 2025-08-15 11:36:08 +03:00
extractor copy 2.py commit 2025-07-28 16:20:11 +03:00
extractor copy 3.py commit 2025-07-28 16:20:11 +03:00
extractor copy 4 -delthesame1.py commit 2025-07-28 16:20:11 +03:00
extractor copy.py commit 2025-07-28 16:20:11 +03:00
extractor автономный для сбора категорий copy.py commit 2025-07-28 16:20:11 +03:00
extractor автономный для сбора категорий mac.py ZH 2025-10-13 10:27:04 +03:00
extractor автономный для сбора категорий win.py ZH 2025-10-13 10:27:04 +03:00
extractor автономный для списка товаров.py commit 2025-07-28 16:20:11 +03:00
extractor вывод всего содержимого json в файлах.py commit 2025-07-28 16:20:11 +03:00
extractor.py Decathlon fix color 2025-10-16 10:32:49 +03:00
links.xlsx commit 2025-07-28 16:20:11 +03:00
main.py ZARAHOME 2.0 2025-08-15 11:36:08 +03:00
parse_settings.json commit 2025-07-28 16:20:11 +03:00
readme.md ZARAHOME 2.0 2025-08-15 11:36:08 +03:00
records_folder.zip commit 2025-07-28 16:20:11 +03:00
request_settings.json commit 2025-07-28 16:20:11 +03:00
requester.py commit 2025-07-28 16:20:11 +03:00
result.xlsx commit 2025-07-28 16:20:11 +03:00
state_dump_1748005445.json commit 2025-07-28 16:20:11 +03:00
xlsx_recorder просто создает экселевские файлики без json.py ZARAHOME prod 1.0 2025-08-05 13:58:30 +03:00
xlsx_recorder создает и отправляет json с фильтром по цене и меняет запрещенные символы.py ZARAHOME 2.0 2025-08-15 11:36:08 +03:00
xlsx_recorder.py фикс ошибки при сборке ZH для пустых значений описания товара 2025-09-23 12:00:31 +03:00

Общее устройство • main.py o Инициализирует окружение (лог-уровень, режимы отправки JSON и т.п.), подхватывает категории из categories.xlsx (через categories.py), запускает экстрактор и рекордер. o По договорённости, переменные окружения: • LOG_LEVEL — уровень логов (DEBUG|INFO|WARNING|ERROR). • SEND_JSON / SAVE_JSON — 0/1 (или False/True) для отправки POST и/или сохранения локальной копии JSON. o Обрабатывает исключения верхнего уровня (не падаем молча). • categories.py o Читает categories.xlsx, отдаёт список URL категорий (пустые/невалидные строки игнорируются). • requester.py o Унифицированная обёртка вокруг HTTP: • parse(url, return_type=None) — делает GET, ретраи, заголовки, куки; при return_type="json" — json.loads(). • Логи HTTP-запросов (в DEBUG видно метод/код/URL). • Контролируемые паузы между повторами при бэд-кодах. o Возвращает None при безнадёжной ошибке (экстрактор учитывает это). • xlsx_recorder.py o Создаёт папку records_folder (если её нет). o Пишет XLSX с «шапкой» колонок и данными. o Имя файла санитизируется (убираются/заменяются проблемные символы типа ? : * " < > | \ /), чтобы windows/mac не ругались. • extractor.py (ядро) o Класс Extractor выбирает метод в зависимости от parse_settings.json["method"]. o Для ZaraHome — метод zarahome_extract_method. Остальные магазины пока «заглушены» (сообщают, что отключены), но исходные заготовки/сигнатуры сохранены, чтобы parse_settings не падал.

Поток данных (Zara Home)

  1. Старт по категории o Загружаем HTML категории; парсим #serverApp-state (большой JSON от сайта). o Определяем category_id. Ищем продуктовый ключ /category/{id}/product... в state.
  2. Получение списка товаров в категории o Если в state сразу есть массив products — берём «сводки» оттуда. o Если есть только списки ID (productIds, sortedProductIds...) — тянем товары пачками через API: o https://www.zarahome.com/itxrest/3/catalog/store/85009924/80290000/productsArray?languageId=-1&productIds=ID1,ID2,...&appId=1 o Размер пачки ~2050 ID (выбираем безопасно, чтобы не словить таймауты/блокировки). o Итог: «список сводок» товаров по категории (summaries).
  3. Проход по товарам и разворачивание вариаций o Для каждой сводки: • Если в ней уже есть detail.colors — это единичный товар, обрабатываем как «vprod». • Если это «bundled» — пробегаем по bundleProductSummaries. • Если вообще нет цветов — считаем «моно-вариант». o На каждом «vprod» берём: • name, detail.displayReference (article), price (в копейках), weight, и т.д. • Состав/уход/происхождение: • compositionDetail.parts → через нашу функцию extract_components_zarahome() собираем читаемую строку. • care[] → список описаний, склеенных переносами. • trace (страна изготовления) — берём из поля country у конкретного size и формируем строку Страна изготовления {COUNTRY} (если есть). • Каталожный путь: из sectionNameEN, familyName, subFamilyName (что пришло в конкретном vprod). Склеивается как Каталог/ZaraHome/
    // (пустые звенья выкидываются).
  4. Цвета и размеры o Проходим detail.colors: • clr_name (название цвета), • sizes[] — по каждому размеру берём: • size.name/size.description → склеенный size_full ("{description} ({name})" или просто name), • visibilityValue → поле «Наличие на сайте» (SHOW → в наличии, всё остальное → не в наличии), • price (переводим из копеек в основную валюту), • weight, • sku и partnumber: берём напрямую из полей размера size["sku"], size["partnumber"]. o Картинки цвета (важно, обновлено): • Собираем все deliveryUrl из extraInfo каждого медиа, относящегося к текущему цвету (фильтр по colorCode). • clr_imgs_s = все такие URL (удаляем дубли, порядок сохраняем). • clr_image (превью цвета) — выбираем единственный кадр из тех же медиа по правилу: • смотрим только медиа с clazz == 3 (ракурс R), • среди них приоритет кадрам, у которых deliveryUrl содержит "-r1/", если таких нет — берём первый с "-r/", • если вообще нет clazz == 3 — фолбэк: превью из clr["image"]["url"] + "_3_1_0.jpg".
  5. Фильтрация дублей (DEL_SAME) o Опциональная логика (включается флагом DEL_SAME = "YES"): • Сначала группируем позиции по ключу: (article, name, clr_name, size_full, price). • Если в группе одна позиция — оставляем. • Если несколько:
  6. Если все partnumber одинаковые — оставляем любую одну (остальные выкидываем).
  7. Если partnumber различаются: • Сначала смотрим visibilityValue: • если в группе есть SHOW и нет противоречий по «короткому артикулу» (см. ниже) — оставляем только SHOW. • если vis у всех одинаковый → идём к проверке «короткого артикула». • «Короткий артикул» vs PartNumber: сравниваем article[:4] и partnumber[1:5]. • если совпадают — оставляем только те, у кого совпали 4 символа; • если не совпадают — удаляем такой элемент как «лишний вариант». • В итоге из каждой группы остаётся максимум 1 строка. o Вся фильтрация выполняется в памяти, уже после сбора всех строк по категории, до записи в XLSX/JSON. Это резко ускорило работу (запись — один раз в конце).
  8. Запись в XLSX o Формируем шапку и строки в точной последовательности, как ожидает ваш шаблон. o Имя файла — хвост URL категории, очищенный от запрещённых символов.
  9. Формирование JSON и отправка POST o Для каждой строки сначала проверяем «ценовой фильтр»: • MIN_PRICE <= cost <= MAX_PRICE (включительно) — только такие попадают в JSON/POST. o Формируем объект: o { o "items": [ o { o "category": { "name": "<очищенный путь без 'Каталог/ZaraHome/'>" }, o "variant": { o "status_id": 1, o "color": "<ClrName, Первая Заглавная>", o "sku": "
    -", o "size": "<size_full с
    >", o "cost": <price округлён вверх до целого>, o "originalUrl": "<url_full>", o "originalName": "<Name, Первая заглавная, остальное как есть>", o "originalDescription": "<longDescription + care + 'Страна изготовления ...' склеены через
    >", o "originalComposition": "<comp_txt с
    >", o "images": ["<список clr_imgs_s>"], o "inStock": <true если vis == 'SHOW'>, o "weight": <вес кг, ceil(граммы/1000)> o }, o "brand": { "name": "zara-home" } o } o ], o "parserName": "zara-home" o } o Нормализация category.name: из cat_path убираем префикс Каталог/ZaraHome/, затем заменяем все спецсимволы, кроме / и -, на _ (регулярка по сути [^\w\/-]+ → _). o Все \n в size_full и comp_txt заменяем на
    . o originalDescription — это longDescription, затем care (каждую строку), затем наша строка Страна изготовления ... — склеиваем через
    , все \n →
    . o Отправка: POST на http://localhost:3005/parser/data с JSON-телом (если SEND_JSON=1). o Сохранение локально: если SAVE_JSON=1, пишем JSON-файл рядом (имя файла включает timestamp и ключ категории; расширение .json). o Если цена вне диапазона — позиция остаётся только в XLSX (в JSON не попадает).
  10. Исключение по материалам (exclusion_materials.txt) o Путь: в корне проекта (рядом с кодом), имя exclusion_materials.txt. o Формат: строки вида "glass","kniv","knif"," steel ", запятая — разделитель, кавычки обязательны (пробелы внутри кавычек учитываются). o Для каждого товара берём только поле comp_txt и приводим к одному регистру. o Если вхождение любой строки из словаря встречается как подстрока (без требований к границам слова), товар исключается из JSON/POST (из XLSX не исключаем). o Сравнение регистронезависимое. o Если файл отсутствует — считаем список исключений пустым.

Обработка картинок (детально) • Источник — данные варианта (конкретного colorCode) из detail.xmedia. • Мы больше не конструируем пути из idMedia + "2.jpg" и не используем mediaLocations для ссылок. • Берём «как есть» extraInfo.deliveryUrl (это уже абсолютный CDN-URL), причём: o Для списка Изображения варианта (clr_imgs_s) — все deliveryUrl для текущего цвета, кроме clazz == 3 (ракурсы r/r1 отфильтрованы). o Для clr_image — выбираем один кадр из clazz == 3 по приоритету -r1/ → -r/ (если нет — фолбэк к превью …_3_1_0.jpg из clr['image']['url']). • Дубликаты удаляем, порядок — как в исходных массивах. (Если когда-нибудь понадобится вернуть сортировку по xmediaLocations и/или учитывать только location == 0, это можно включить отдельно: у нас уже были патчи, но на текущей ревизии выбрана стратегия “все deliveryUrl текущего цвета, минус clazz==3 для списка и с отдельным выбором превью”).

Логирование • Единый логер с форматированием времени/уровня/сообщения. • LOG_LEVEL управляет подробностью. • В DEBUG видно: o Запуски категорий/количество продуктов, o HTTP запросы (метод/код/URL), o Ключевые точки преобразований (при необходимости можно включать точечные log.debug() в «узких местах» — выбор clr_image, выкидывание дублей, отбор по цене и т.п.).

Конфигурация/переключатели • DEL_SAME = "YES"|"NO" — включение/выключение продвинутой фильтрации дублей (по (article, name, clr_name, size_full, price, partnumber, vis)). • MIN_PRICE, MAX_PRICE — границы цены для попадания в JSON/POST (включительные). • SEND_JSON / SAVE_JSON — 0/1, можно передать через env или (если так реализовано у вас в main.py) спросить у пользователя интерактивно при запуске, когда переменные не заданы. • Путь к exclusion_materials.txt — корень проекта.

Производительность • Сбор всей категории в память, затем фильтрации (дубли/исключения/ценовой фильтр), затем единичная запись XLSX/JSON → резко быстрее, чем писать строки по одной. • API пачками по productIds (сбалансированный размер пачки). • Минимум повторных запросов на одну карточку.

Отказоустойчивость/краевые случаи • Если не нашли category_id в serverApp-state — категория пропускается (логируется ошибка). • Если products пуст или productIds пуст — логируем: «no products in this category». • Если по размеру отсутствует sku/partnumber — пишем пустые строки (а sku в JSON формируем аккуратно, чтобы не получить "-"). • Если deliveryUrl отсутствует — картинка цвета уходит в фолбэк (см. выше), список картинок может быть пуст. • Если нет ни sectionNameEN/familyName/subFamilyName — cat_path укорачивается до того, что есть (или пусто), а category.name в JSON корректно нормализуется. • Если comp_txt пустой, модуль исключений просто ничего не найдёт. • Если хост localhost:3005 недоступен — логируем ошибку POST; XLSX и локальные JSON (при SAVE_JSON=1) при этом остаются.

Что «самое важное» мы поменяли в 2.0

  1. Развели сбор картинок: список картинок варианта (clr_imgs_s) теперь из deliveryUrl, а не из конкатенации idMedia + "2.jpg".
  2. Выбор превью цвета (clr_image) — строго из clazz == 3 с приоритетом -r1/ → -r/ (вместо «случайных» кропов).
  3. Фильтрация дублей вынесена до записи (по группам, как описано выше) → существенный выигрыш по скорости и стабильности размера XLSX.
  4. Ценовой фильтр и исключения материалов влияют только на JSON/POST; XLSX остаётся полной «сырым» логом категории.
  5. Нормализация category.name для JSON (без «Каталог/ZaraHome/» и без мусорных символов).
  6. Логи — вместо print, с уровнем подробности через LOG_LEVEL.