import sys
import random
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton, QLineEdit, QLabel, QSpinBox, QTextEdit, QMessageBox, QProgressBar, QFileDialog, QFormLayout, QGroupBox, QHBoxLayout
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.common.exceptions import NoSuchElementException, ElementClickInterceptedException, WebDriverException
from webdriver_manager.chrome import ChromeDriverManager
import time
import os
import pandas as pd
import re

class BrowserAutomationApp(QWidget):
    def __init__(self):
        super().__init__()
        self.delay_min = 1  # Минимальная задержка по умолчанию
        self.delay_max = 10  # Максимальная задержка по умолчанию
        self.page_delay = 5  # Задержка между прокрутками страниц по умолчанию
        self.initUI()
        self.driver = None
        self.titles = []  # Инициализация списка заголовков
        self.errors = []

    def initUI(self):
        self.setWindowTitle('Автоматизация браузера')

        layout = QVBoxLayout()

        self.url_label = QLabel('URL:')
        self.url_input = QLineEdit(self)
        self.count_label = QLabel('Количество:')
        self.count_input = QSpinBox(self)
        self.count_input.setMinimum(1)
        self.count_input.setMaximum(2147483647)  # Установка максимального значения на 2147483647
        self.count_input.setValue(10)
        self.start_button = QPushButton('Старт', self)
        self.start_button.clicked.connect(self.start_automation)
        self.export_button = QPushButton('Экспорт', self)
        self.export_button.clicked.connect(self.export_to_file)
        self.logs_button = QPushButton('Логи', self)
        self.logs_button.clicked.connect(self.toggle_logs)
        self.settings_button = QPushButton('Настройки', self)
        self.settings_button.clicked.connect(self.toggle_settings)

        self.output_label = QLabel('Вывод:')
        self.output_text = QTextEdit(self)
        self.output_text.setReadOnly(True)

        self.log_label = QLabel('Логи:')
        self.log_text = QTextEdit(self)
        self.log_text.setReadOnly(True)
        self.log_text.setVisible(False)  # Скрыть текстовое поле логов

        self.progress_label = QLabel('Прогресс:')
        self.progress_bar = QProgressBar(self)
        self.progress_bar.setValue(0)

        self.current_count_label = QLabel('Спарсено: 0 / 0')

        # Настройки
        self.settings_group = QGroupBox('Настройки')
        self.settings_layout = QFormLayout()

        self.delay_min_label = QLabel('Минимальная задержка между парсингом заголовков (сек):')
        self.delay_min_input = QSpinBox()
        self.delay_min_input.setMinimum(1)
        self.delay_min_input.setMaximum(10)
        self.delay_min_input.setValue(self.delay_min)

        self.delay_max_label = QLabel('Максимальная задержка между парсингом заголовков (сек):')
        self.delay_max_input = QSpinBox()
        self.delay_max_input.setMinimum(1)
        self.delay_max_input.setMaximum(10)
        self.delay_max_input.setValue(self.delay_max)

        self.page_delay_label = QLabel('Задержка между прокруткой страниц (сек):')
        self.page_delay_input = QSpinBox()
        self.page_delay_input.setMinimum(1)
        self.page_delay_input.setMaximum(10)
        self.page_delay_input.setValue(self.page_delay)

        self.settings_layout.addRow(self.delay_min_label, self.delay_min_input)
        self.settings_layout.addRow(self.delay_max_label, self.delay_max_input)
        self.settings_layout.addRow(self.page_delay_label, self.page_delay_input)
        self.settings_group.setLayout(self.settings_layout)
        self.settings_group.setVisible(False)  # Скрыть настройки по умолчанию

        self.save_settings_button = QPushButton('Сохранить', self)
        self.save_settings_button.clicked.connect(self.save_settings)

        settings_hbox = QHBoxLayout()
        settings_hbox.addWidget(self.save_settings_button)
        settings_hbox.addStretch(1)

        self.settings_layout.addRow(settings_hbox)

        layout.addWidget(self.url_label)
        layout.addWidget(self.url_input)
        layout.addWidget(self.count_label)
        layout.addWidget(self.count_input)
        layout.addWidget(self.start_button)
        layout.addWidget(self.export_button)
        layout.addWidget(self.logs_button)
        layout.addWidget(self.settings_button)
        layout.addWidget(self.settings_group)
        layout.addWidget(self.output_label)
        layout.addWidget(self.output_text)
        layout.addWidget(self.log_label)
        layout.addWidget(self.log_text)
        layout.addWidget(self.progress_label)
        layout.addWidget(self.progress_bar)
        layout.addWidget(self.current_count_label)

        self.setLayout(layout)

    def toggle_settings(self):
        self.settings_group.setVisible(not self.settings_group.isVisible())

    def save_settings(self):
        self.delay_min = self.delay_min_input.value()
        self.delay_max = self.delay_max_input.value()
        self.page_delay = self.page_delay_input.value()
        print(f"Сохранено: delay_min={self.delay_min}, delay_max={self.delay_max}, page_delay={self.page_delay}")  # Отладка
        self.settings_group.setVisible(False)  # Скрыть настройки после сохранения
        self.show_save_confirmation()

    def show_save_confirmation(self):
        msg = QMessageBox()
        msg.setIcon(QMessageBox.Information)
        msg.setText("Настройки сохранены")
        msg.setWindowTitle("Подтверждение")
        msg.exec_()

    def toggle_logs(self):
        self.log_text.setVisible(not self.log_text.isVisible())

    def start_automation(self):
        url = self.url_input.text()
        count = self.count_input.value()

        if not self.driver:
            self.init_driver()

        try:
            self.driver.get(url)
            time.sleep(2)  # Ожидание загрузки страницы

            self.titles = []  # Очистка списка заголовков перед началом парсинга
            elements = self.driver.find_elements(By.CSS_SELECTOR, 'a.bulletinLink.bull-item__self-link.auto-shy')
            total_elements = min(count, len(elements))

            while len(self.titles) < count:
                self.driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
                time.sleep(self.page_delay)  # Увеличение задержки для ожидания загрузки новых элементов
                elements = self.driver.find_elements(By.CSS_SELECTOR, 'a.bulletinLink.bull-item__self-link.auto-shy')

                for element in elements[len(self.titles):]:
                    title = element.text
                    match = re.search(r'(\w+)\s*/\s*(\w+)', title)
                    if match:
                        brand = match.group(1)
                        article = match.group(2)
                        self.titles.append([brand, article])
                        self.output_text.append(f'{brand} / {article}')
                    else:
                        self.output_text.append(f'No match found for: {title}')

                    QApplication.processEvents()  # Обновление интерфейса
                    delay = random.randint(self.delay_min, self.delay_max)
                    print(f"Задержка между парсингом заголовков: {delay} секунд")  # Отладка
                    time.sleep(delay)  # Случайная задержка между парсингом заголовков от минимальной до максимальной
                    self.progress_bar.setValue(int((len(self.titles) / count) * 100))  # Преобразование значения в целое число
                    self.current_count_label.setText(f'Спарсено: {len(self.titles)} / {count}')  # Обновление метки

                    if len(self.titles) >= count:
                        break

        except NoSuchElementException as e:
            self.errors.append(f'Ошибка: {str(e)}')
            self.show_captcha_popup()
        except ElementClickInterceptedException as e:
            self.errors.append(f'Ошибка: {str(e)}')
            self.show_captcha_popup()
        except WebDriverException as e:
            self.errors.append(f'Ошибка WebDriver: {str(e)}')
            self.show_error_popup("Ошибка WebDriver", str(e))
        except Exception as e:
            self.errors.append(f'Неожиданная ошибка: {str(e)}')
            self.show_error_popup("Неожиданная ошибка", str(e))

    def init_driver(self):
        try:
            options = webdriver.ChromeOptions()
            options.add_argument('--start-maximized')
            options.add_argument(f'user-data-dir={os.path.join(os.path.expanduser("~"), ".config", "google-chrome")}')
            self.driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options)
        except WebDriverException as e:
            self.errors.append(f'Ошибка WebDriver: {str(e)}')
            self.show_error_popup("Ошибка WebDriver", str(e))

    def export_to_file(self):
        if not self.titles:
            self.output_text.append('\nНет данных для экспорта. Сначала запустите автоматизацию.')
            return

        file_path, file_format = QFileDialog.getSaveFileName(self, "Сохранить файл", "", "Excel Files (*.xlsx);;CSV Files (*.csv)")
        if file_path:
            df = pd.DataFrame(self.titles, columns=['Brand', 'Article'])
            if file_format == "Excel Files (*.xlsx)":
                df.to_excel(file_path, index=False)
                self.output_text.append(f'\nДанные экспортированы в {file_path}')
            elif file_format == "CSV Files (*.csv)":
                df.to_csv(file_path, index=False, encoding='utf-8-sig', sep=';')  # Использование кодировки utf-8-sig и точки с запятой в качестве разделителя
                self.output_text.append(f'\nДанные экспортированы в {file_path}')

    def show_logs(self):
        self.log_text.setVisible(True)
        self.log_text.clear()
        for error in self.errors:
            self.log_text.append(error)

    def show_captcha_popup(self):
        self.show_error_popup("Обнаружена капча", "Пожалуйста, решите капчу вручную и попробуйте снова.")

    def show_error_popup(self, title, message):
        msg = QMessageBox()
        msg.setIcon(QMessageBox.Warning)
        msg.setText(title)
        msg.setInformativeText(message)
        msg.setWindowTitle("Ошибка")
        msg.exec_()

    def closeEvent(self, event):
        if self.driver:
            self.driver.quit()
        event.accept()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = BrowserAutomationApp()
    ex.show()
    sys.exit(app.exec_())
поменяй на другой интерфейс GUI