import re
import pandas as pd
from bs4 import BeautifulSoup
import logging
import os
from openpyxl import load_workbook
from openpyxl.styles import Alignment
from openpyxl.utils import get_column_letter

logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s - %(levelname)s - %(message)s')


def parse_product_page(html):
    soup = BeautifulSoup(html, 'html.parser')

    # Parsing product category
    breadcrumbs = soup.find('div', class_='bx-breadcrumb')
    category = breadcrumbs.find_all(
        'span', itemprop='name')[-1].text.strip() if breadcrumbs else 'Категория не найдена'

    # Parsing product name
    name_tag = soup.find('h1', class_='npc__name')
    name = name_tag.text.strip() if name_tag else 'Название товара не найдено'
    article = name_tag.find('span', class_='npc__article').text.strip(
    ) if name_tag and name_tag.find('span', class_='npc__article') else ''
    name = name.replace(article, '').strip() if article in name else name

    details_blocks = soup.find_all('div', class_='npc__details')

    # Looking for the second block (index 1, as numbering starts from 0)
    if len(details_blocks) >= 2:
        article_tag = details_blocks[1].find('span', class_='npc__value')
        article = article_tag.text.strip() if article_tag else 'Артикул не найден'
    else:
        article = 'Не удалось найти артикул'

    # Parsing product price
    price_tag = soup.find('div', class_='npc__price')
    price = price_tag.text.strip() if price_tag else 'Цена не найдена'
    price = re.sub(r'[^\d\s,₽]', '', price).strip()

    # Parsing product availability
    availability_details_block = soup.find_all(
        'div', class_='col-default-4 col-tablet-12')
    availability_tag = availability_details_block[0].find(
        'span', class_='npc__value')
    availability = availability_tag.text.strip(
    ) if availability_tag else 'Наличие не найдено'

    # Parsing product analogs
    analogs = []
    analog_groups = soup.find_all('div', class_='result-table__group')
    for group in analog_groups:
        brand = group.find('span', class_='result-table__info-brand').text.strip() if group.find(
            'span', class_='result-table__info-brand') else 'Бренд аналога не найден'
        article_analog = group.find('a', class_='result-table__info-article').text.strip(
        ) if group.find('a', class_='result-table__info-article') else 'Артикул аналога не найден'
        price_analog_tag = group.find(
            'div', class_='result-table__part-cell price')
        price_analog = price_analog_tag.text.strip(
        ) if price_analog_tag else 'Цена аналога не найдена'
        price_analog = re.sub(r'[^\d\s,₽]', '', price_analog).strip()

        # Parsing analog availability
        availability_analog_tag = group.find(
            'div', class_='result-table__part-cell in-stock')
        availability_analog = availability_analog_tag.find('span').text.strip(
        ) if availability_analog_tag and availability_analog_tag.find('span') else 'Наличие аналога не найдено'
        availability_analog = re.sub(r'[^\d]', '', availability_analog).strip()

        analogs.append({
            'Brand': brand,
            'Article': article_analog,
            'Price': price_analog,
            'Availability': availability_analog
        })

    if not analogs:
        analog_not_found = soup.find('div', class_='article-not-found')
        if analog_not_found:
            analogs.append(
                {'Brand': 'Аналогов нет', 'Article': '', 'Price': '', 'Availability': ''})
        else:
            analogs.append({'Brand': 'Ошибка выгрузки Аналогов',
                            'Article': '', 'Price': '', 'Availability': ''})

    return {
        'Category': category,
        'Name': name,
        'Article': article,
        'Availability': availability,
        'Price': price,
        'Analogs': analogs
    }


def parse_html_directory(directory_path):
    data = []
    for filename in os.listdir(directory_path):
        if filename.endswith('.html'):
            file_path = os.path.join(directory_path, filename)
            with open(file_path, 'r', encoding='utf-8') as file:
                html = file.read()
                product_data = parse_product_page(html)
                data.append(product_data)
                logging.info(f"Обработан файл: {file_path}")
    return data


def save_to_excel(data, output_file):
    if os.path.exists(output_file):
        existing_wb = load_workbook(output_file)
        existing_ws = existing_wb.active
        start_row = existing_ws.max_row + 1
    else:
        existing_wb = None
        start_row = 2  # Начинаем с 2, чтобы оставить место для заголовков

    new_rows = []
    for product in data:
        base_row = {
            'Category': product['Category'],
            'Name': product['Name'],
            'Article': product['Article'],
            'Availability': product['Availability'],
            'Price': product['Price'],
            'Brand': None,
            'Analog Article': None,
            'Analog Price': None,
            'Analog Availability': None,
        }

        # Если есть аналоги, добавляем информацию о них
        if product['Analogs']:
            for analog in product['Analogs']:
                analog_row = base_row.copy()
                analog_row.update({
                    'Brand': analog['Brand'],
                    'Analog Article': analog['Article'],
                    'Analog Price': analog['Price'],
                    'Analog Availability': analog['Availability'],
                })
                new_rows.append(analog_row)
        else:
            # Если аналогов нет, значение аналогов остаются пустыми
            new_rows.append(base_row)

    new_df = pd.DataFrame(new_rows)

    # Записываем данные в Excel
    if existing_wb:
        with pd.ExcelWriter(output_file, engine='openpyxl', mode='a', if_sheet_exists='overlay') as writer:
            new_df.to_excel(writer, index=False, header=False,
                            startrow=start_row - 1, sheet_name='Products')
            worksheet = writer.sheets['Products']
    else:
        with pd.ExcelWriter(output_file, engine='openpyxl', mode='w') as writer:
            new_df.to_excel(writer, index=False, sheet_name='Products')
            worksheet = writer.sheets['Products']

    if existing_wb:
        existing_wb.close()

    try:
        workbook = load_workbook(output_file)
        worksheet = workbook.active

        # Объединение ячеек и форматирование
        row = start_row
        while row <= worksheet.max_row:
            current_category = worksheet.cell(row=row, column=1).value
            start_merge_row = row

            # Проверка точки начала для объединения строк
            while (row <= worksheet.max_row and
                   worksheet.cell(row=row, column=1).value == current_category):
                row += 1

            end_merge_row = row - 1

            # Выполняем объединение ячеек только если need to combine
            if end_merge_row > start_merge_row:
                for col in range(1, 6):  # Объединяем столбцы с 1 по 5
                    worksheet.merge_cells(start_row=start_merge_row,
                                          end_row=end_merge_row,
                                          start_column=col,
                                          end_column=col)
                    cell = worksheet.cell(row=start_merge_row, column=col)
                    cell.alignment = Alignment(vertical='center')

            row = end_merge_row + 1

        # Автоподбор ширины колонок
        for col_num, column in enumerate(worksheet.columns, start=1):
            max_length = 0
            for cell in column:
                if cell.value is not None:
                    max_length = max(max_length, len(str(cell.value)))
            adjusted_width = max_length + 2
            worksheet.column_dimensions[get_column_letter(
                col_num)].width = adjusted_width

        workbook.save(output_file)

        logging.info(f"Данные успешно сохранены в файл: {output_file}")
    except Exception as e:
        logging.error(f"Ошибка при сохранении данных в файл: {e}")


if __name__ == "__main__":
    directory_path = r'C:\Py\pars_store\path\result_html'
    output_file = 'ХЕ.xlsx'

    data = parse_html_directory(directory_path)
    save_to_excel(data, output_file)



С кодом проблема. В директории с сохранёнными страницами может быть любое количество страниц, все эти страницы должны быть обработаны программой и все необходимые данные с каждой страницы должны быть выгружены в exel. В данный момент программа некорректно выгружает данные в exel. Если на странице с которой работает программа, один или 0 аналогов, то происходит ерунда. Нужно чтобы страницы на которых 0 или 1 аналог тоже сохранялись в новой строке, данные о товаре корректно расположены на против аналогов.