diff --git a/Parsing ZARAHOME/src/xlsx_recorder просто создает экселевские файлики без json.py b/Parsing ZARAHOME/src/xlsx_recorder просто создает экселевские файлики без json.py
new file mode 100644
index 0000000..5e5f1ad
--- /dev/null
+++ b/Parsing ZARAHOME/src/xlsx_recorder просто создает экселевские файлики без json.py
@@ -0,0 +1,23 @@
+from openpyxl import Workbook
+
+from os.path import isdir, abspath
+from os import mkdir
+
+# объект для сохранения спаршенных категорий в таблицы
+class Recorder:
+ def __init__(self, records_folder="category_parsed"):
+ # проверяем наличие папки для сохранения таблиц
+ if not isdir(abspath('records_folder')):
+ mkdir(abspath("records_folder"))
+ self.record_folder = abspath("records_folder")
+
+ # запись и сохранение таблицы
+ def record(self, csv_name, table_data):
+ workbook = Workbook()
+ worksheet = workbook.active
+
+
+ for row in table_data:
+ worksheet.append(row)
+
+ workbook.save(f"{self.record_folder}/{csv_name}.xlsx")
\ No newline at end of file
diff --git a/Parsing ZARAHOME/src/xlsx_recorder.py b/Parsing ZARAHOME/src/xlsx_recorder.py
index 5e5f1ad..59d38e7 100644
--- a/Parsing ZARAHOME/src/xlsx_recorder.py
+++ b/Parsing ZARAHOME/src/xlsx_recorder.py
@@ -1,23 +1,105 @@
+# xlsx_recorder.py · расширен отправкой JSON
from openpyxl import Workbook
-
-from os.path import isdir, abspath
+from os.path import isdir, abspath, join
from os import mkdir
+import re, json, math, logging, requests, os
-# объект для сохранения спаршенных категорий в таблицы
+log = logging.getLogger("recorder")
+
+# ─────────────────────── настройки ───────────────────────
+SEND_JSON = True # отправка POST
+SAVE_JSON = True # сохранять копию JSON
+POST_URL = "http://localhost:3005/parser/data"
+
+INVALID_CHARS = r'[<>:"/\\|*?]'
+def sanitize_filename(name: str, repl: str = "_") -> str:
+ """Удаляет/заменяет символы, запрещённые в именах файлов."""
+ clean = re.sub(INVALID_CHARS, repl, name)
+ return clean.split("?", 1)[0].strip()
+
+# объект для сохранения спаршенных категорий
class Recorder:
- def __init__(self, records_folder="category_parsed"):
- # проверяем наличие папки для сохранения таблиц
- if not isdir(abspath('records_folder')):
- mkdir(abspath("records_folder"))
- self.record_folder = abspath("records_folder")
+ def __init__(self, records_folder="records_folder"):
+ # создаём папку при необходимости
+ rf_abs = abspath(records_folder)
+ if not isdir(rf_abs):
+ mkdir(rf_abs)
+ self.record_folder = rf_abs
- # запись и сохранение таблицы
- def record(self, csv_name, table_data):
- workbook = Workbook()
- worksheet = workbook.active
+ # запись таблицы + JSON/POST
+ def record(self, csv_name, table):
+ csv_name = sanitize_filename(csv_name)
+ # ─── 1) сохраняем XLSX ─────────────────────────────
+ wb = Workbook()
+ ws = wb.active
+ for row in table:
+ ws.append(row)
+ xlsx_path = join(self.record_folder, f"{csv_name}.xlsx")
+ wb.save(xlsx_path)
+ log.info("XLSX saved → %s", xlsx_path)
- for row in table_data:
- worksheet.append(row)
+ # ─── 2) формируем JSON (по утверждённым правилам) ──
+ headers = table[0]
+ idx = {h: i for i, h in enumerate(headers)}
- workbook.save(f"{self.record_folder}/{csv_name}.xlsx")
\ No newline at end of file
+ items = []
+ for row in table[1:]:
+ # базовые поля
+ article = row[idx["Артикул"]]
+ partnumber = row[idx["PartNumber"]]
+ size_full = row[idx["Свойство: Размер"]].replace("\n", "
")
+ price_raw = row[idx["Цена закупки"]]
+ price_int = math.ceil(float(price_raw))
+ clr_name_raw = row[idx["Свойство: Цвет"]]
+ clr_name = clr_name_raw.capitalize()
+ vis = row[idx["Наличие на сайте"]]
+ weight_gram = float(row[idx["Свойство: Вес(г)"]]) if row[idx["Свойство: Вес(г)"]] else 0.0
+ weight_kg = math.ceil(weight_gram / 1000) if weight_gram else 0
+
+ # составляем объект
+ variant = {
+ "status_id": 1,
+ "color": clr_name,
+ "sku": f"{article}-{partnumber}",
+ "size": size_full,
+ "cost": price_int,
+ "originalUrl": row[idx["Краткое описание"]], # url_full в таблице
+ "originalName": row[idx["Название товара или услуги"]].capitalize(),
+ "originalDescription": (
+ row[idx["Полное описание"]].replace("\n", "
") + "
" +
+ row[idx["Параметр: Уход"]].replace("\n", "
") + "
" +
+ row[idx["Параметр: Происхождение"]].replace("\n", "
")
+ ).strip("
"),
+ "originalComposition": row[idx["Параметр: Состав"]].replace("\n", "
"),
+ "images": [img for img in row[idx["Изображения варианта"]].split("\n") if img],
+ "inStock": vis == "SHOW",
+ "weight": weight_kg
+ }
+
+ category_name = re.sub(INVALID_CHARS, "_",
+ row[idx["Размещение на сайте"]]
+ .replace("Каталог/ZaraHome/", ""))
+ items.append({
+ "category": {"name": category_name},
+ "variant": variant,
+ "brand": {"name": "zara-home"}
+ })
+
+ payload = {"items": items, "parserName": "zara-home"}
+
+ # ─── 3) сохраняем JSON при необходимости ───────────
+ if SAVE_JSON:
+ json_path = join(self.record_folder, f"{csv_name}.json")
+ with open(json_path, "w", encoding="utf-8") as fh:
+ json.dump(payload, fh, ensure_ascii=False, indent=2)
+ log.info("JSON saved → %s", json_path)
+
+ # ─── 4) POST на локальный сервис ───────────────────
+ if SEND_JSON:
+ try:
+ resp = requests.post(POST_URL, json=payload, timeout=20)
+ resp.raise_for_status()
+ log.info("POST %s OK (%s items)", csv_name, len(items))
+ except Exception as err:
+ log.warning("POST %s FAILED: %s", csv_name, err)