MacOS_Parsers/Processing/0_02_слияние_всех эксель файлов ZARAHOME.py

187 lines
6.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import os
import sys
import traceback
import pandas as pd
from datetime import datetime
# === Вспомогательное ===
def get_script_dir() -> str:
try:
return os.path.dirname(os.path.abspath(__file__))
except NameError:
return os.getcwd()
def log(msg: str):
ts = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
line = f'[{ts}] {msg}'
print(line)
try:
with open(log_file, 'a', encoding='utf-8') as f:
f.write(line + '\n')
except Exception:
pass
def is_temp_or_hidden(name: str) -> bool:
return name.startswith('~$') or name.startswith('.')
def build_ozonart(df: pd.DataFrame) -> pd.DataFrame:
"""
Создаёт/перезаписывает колонку OZONart по правилу:
- если оба значения (Артикул, PartNumber) непустые -> 'Артикул-PartNumber'
- иначе -> ''
Под "пустым" понимаем NaN/None/пустая строка/строка из пробелов.
"""
if 'Артикул' not in df.columns or 'PartNumber' not in df.columns:
# Если вдруг где-то нет нужных колонок — оставим пустую OZONart и залогируем
if 'OZONart' not in df.columns:
df['OZONart'] = ''
log('ПРЕДУПРЕЖДЕНИЕ: Отсутствует колонка "Артикул" или "PartNumber" — OZONart заполнен пустыми значениями.')
return df
art = df['Артикул']
part = df['PartNumber']
# Признак непустоты: не NaN и не пустая строка после strip()
art_nonempty = art.notna() & art.astype(str).str.strip().ne('')
part_nonempty = part.notna() & part.astype(str).str.strip().ne('')
mask = art_nonempty & part_nonempty
# По умолчанию — пустые строки
ozon = pd.Series([''] * len(df), index=df.index, dtype=object)
# Там, где оба непустые — склейка
ozon.loc[mask] = art.loc[mask].astype(str).str.strip() + '-' + part.loc[mask].astype(str).str.strip()
df['OZONart'] = ozon
# Попробуем разместить OZONart сразу после PartNumber
try:
cols = list(df.columns)
if 'OZONart' in cols and 'PartNumber' in cols:
cols.remove('OZONart')
idx = cols.index('PartNumber') + 1
cols.insert(idx, 'OZONart')
df = df.reindex(columns=cols)
except Exception:
# Не критично — просто оставим как есть
pass
return df
# === Пути ===
script_dir = get_script_dir()
folder_path = os.path.join(script_dir, 'Files-todo')
timestamp = datetime.now().strftime('%Y%m%d-%H%M')
output_filename = f'All-todo-{timestamp}.xlsx'
output_file = os.path.join(folder_path, output_filename)
log_file = os.path.join(folder_path, 'merge_log.txt')
BASE_URL = "https://www.zarahome.com/pl/en/"
def main():
log('=== Старт объединения Excel-файлов ===')
log(f'Папка: {folder_path}')
if not os.path.isdir(folder_path):
log(f'ОШИБКА: Папка не найдена: {folder_path}')
sys.exit(1)
names = sorted(os.listdir(folder_path))
files = []
for name in names:
if is_temp_or_hidden(name):
continue
if not name.lower().endswith('.xlsx'):
continue
if name.startswith('All-todo-'):
continue
full = os.path.join(folder_path, name)
if os.path.isfile(full):
files.append(full)
if not files:
log('Нет входных .xlsx файлов для слияния. Завершение.')
return
log(f'Найдено файлов: {len(files)}')
dfs = []
all_columns = []
seen_cols = set()
processed = 0
errors = 0
for i, path in enumerate(files, start=1):
fname = os.path.basename(path)
try:
df = pd.read_excel(path, engine='openpyxl')
if df is None or df.empty:
log(f'ПРЕДУПРЕЖДЕНИЕ: Пустой файл — пропуск: {fname}')
continue
# Добавляем колонку OZONart согласно правилу
df = build_ozonart(df)
# Зафиксируем исходный порядок колонок первого удачного файла
if not all_columns:
for c in df.columns:
if c not in seen_cols:
all_columns.append(c)
seen_cols.add(c)
# Добавляем служебные источники
stem, _ = os.path.splitext(fname)
df['SourceFile'] = fname
df['SourceFileUrl'] = BASE_URL + stem
dfs.append(df)
processed += 1
log(f'[{i}/{len(files)}] OK: {fname} — строк: {len(df)}')
except Exception as e:
errors += 1
log(f'[{i}/{len(files)}] ОШИБКА: {fname}: {e}')
log(traceback.format_exc())
if not dfs:
log('Все файлы пустые или не прочитаны — нечего сохранять.')
return
combined = pd.concat(dfs, ignore_index=True)
# Порядок колонок:
# 1) как в первом удачном файле,
# 2) затем прочие (кроме служебных) по алфавиту,
# 3) затем служебные SourceFile и SourceFileUrl в конце.
extra_cols = [c for c in combined.columns if c not in all_columns and c not in ('SourceFile', 'SourceFileUrl')]
extra_cols.sort()
final_cols = all_columns + extra_cols
# Гарантируем размещение OZONart сразу после PartNumber, если они есть
if 'OZONart' in final_cols and 'PartNumber' in final_cols:
final_cols.remove('OZONart')
pn_idx = final_cols.index('PartNumber')
final_cols.insert(pn_idx + 1, 'OZONart')
if 'SourceFile' not in final_cols:
final_cols.append('SourceFile')
if 'SourceFileUrl' not in final_cols:
final_cols.append('SourceFileUrl')
combined = combined.reindex(columns=final_cols)
try:
with pd.ExcelWriter(output_file, engine='openpyxl') as writer:
combined.to_excel(writer, index=False, sheet_name='Sheet')
log(f'Готово: {output_file}')
log(f'Итоговых строк: {len(combined)}')
log(f'Успешно обработано файлов: {processed}, ошибок: {errors}')
except Exception as e:
log(f'ОШИБКА сохранения {output_file}: {e}')
log(traceback.format_exc())
log('=== Готово ===')
if __name__ == '__main__':
main()