Brak aktualizacji paska postępu

Brak aktualizacji paska postępu
Mateusz Sochacki
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 1
0

Cześć,
Uczę się Pythona i próbuję zrobić prostą aplikację dla potrzeb swoich badań, niestety napotkałem problem z paskiem postępu: podczas pracy w ogóle nic na nim się nie wyświetla, czy ktoś z Was mógłby pomóc?
Gdybyście zauważyli jakieś błędy dajcie znać co mogę zrobić by mój kod był lepszy ;)

Kopiuj
    from selenium import webdriver
    from webdriver_manager.chrome import ChromeDriverManager
    from selenium.webdriver.chrome.service import Service
    from selenium.webdriver.chrome.options import Options
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.common.exceptions import TimeoutException
    import pandas as pd
    import time
    import tkinter as tk
    import subprocess
    import os
    import sys
    import threading
    import queue
    from dotenv import load_dotenv
    from tkinter import Tk, Label, StringVar, ttk, filedialog, Entry, Button, Checkbutton, IntVar, BooleanVar
    from datetime import datetime, timedelta, date
    
    def get_login_credentials():
        def submit():
            global username, password
            username, password = username_entry.get(), pass_entry.get()
            root.destroy()
            
        def toggle_password():
            if show_pass.get() == 1:
                pass_entry.config(show='')
            else:
                pass_entry.config(show='*')
        
        root = Tk()
        root.title("Logowanie do Carelink Medtronic")
    
        # Pole - Nazwa użytkownika
        Label(root, text="Nazwa użytkownika:").grid(row=0, column=0, padx=10, pady=10)
        username_entry = Entry(root)
        username_entry.grid(row=0, column=1, padx=10, pady=10)
        username_entry.focus_set() # Ustawienie kursora w polu Nazwa użytkownika
        
        # Pole - Hasło
        Label(root, text="Hasło:").grid(row=1, column=0, padx=10, pady=10)
        pass_entry = Entry(root, show="*")
        pass_entry.grid(row=1, column=1, padx=10, pady=10)
    
        # Checkbox do podglądu hasła
        show_pass = IntVar()
        checkbtn_pass = Checkbutton(root, text="Pokaż hasło", variable=show_pass, command=toggle_password)
        checkbtn_pass.grid(row=2, column=1, padx=10, pady=5)
    
        # Przycisk logowania
        login_button = Button(root, text="Zaloguj", command=submit, state="disabled")
        login_button.grid(row=3, column=0, columnspan=2, pady=10)
    
        # Aktualizacja stanu przycisku logowania
        def update_button_state(*_):
            login_button.config(state="normal" if username_entry.get() and pass_entry.get() else "disabled")
        username_entry.bind("<KeyRelease>", update_button_state)
        pass_entry.bind("<KeyRelease>", update_button_state)
    
        # Obsługa klawisza Enter
        root.bind_all("<Return>", lambda e: submit() if login_button["state"] == "normal" else None)
    
        # Wyśrodkowanie okna
        root.update_idletasks()
        width, height = root.winfo_width(), root.winfo_height()
        x = (root.winfo_screenwidth() - width) // 2
        y = (root.winfo_screenheight() - height) // 2
        root.geometry(f"{width}x{height}+{x}+{y}")
    
        root.mainloop()
    
    get_login_credentials()
    
    # Wybór pliku Excel
    def choose_excel_file():
        root = Tk()
        root.withdraw()
        return filedialog.askopenfilename(title="Wybierz plik Excel z listą pacjentek", filetypes=[("Pliki Excel", "*.xlsx *.xls")])
    
    # Ładowanie danych z Excela
    excel_file = choose_excel_file()
    if excel_file:
        df = pd.read_excel(excel_file)
        required_columns = {'Nazwisko', 'Imię', 'początek ciąży', 'Data porodu'}
        if not required_columns.issubset(df.columns):
            raise ValueError("Brak jednej lub więcej wymaganych kolumn w pliku Excel.")
    
    # Wybór folderu do pobierania CSV
    Tk().withdraw()
    download_folder = filedialog.askdirectory(title="Wybierz folder do zapisania plików CSV")
    if not download_folder:
        raise Exception("Nie wybrano folderu, program zakończony.")
    download_folder = os.path.normpath(download_folder)
    
    # Ustal ścieżkę do folderu "Downloads" lub "Pobrane"
    downloads_folder = os.path.join(os.path.expanduser("~"), "Downloads")
    
    # Funkcja do pobrania wersji Chrome
    def get_chrome_version():
        try:
            result = subprocess.run(['google-chrome', '--version'], capture_output=True, text=True)
            return result.stdout.strip().split(' ')[-1] if result.returncode == 0 else None
        except FileNotFoundError:
            return None
    
    # Funkcja do pobrania wersji ChromeDriver
    def get_chromedriver_version():
        try:
            result = subprocess.run(['chromedriver', '--version'], capture_output=True, text=True)
            return result.stdout.strip().split(' ')[-1] if result.returncode == 0 else None
        except FileNotFoundError:
            return None
    
    # Sprawdzenie wersji i konfiguracja sterownika
    chrome_version = get_chrome_version()
    chromedriver_version = get_chromedriver_version()
    service = Service(ChromeDriverManager().install()) if chrome_version != chromedriver_version else Service()
    
    # Ustawienia opcji Chrome
    chrome_options = Options()
    # chrome_options.add_argument("--headless")  # Uruchomienie w tle
    chrome_options.add_experimental_option("prefs", {"download.default_directory": download_folder})
    driver = webdriver.Chrome(service=service, options=chrome_options)
    driver.get('https://carelink.medtronic.eu/login')
    driver.maximize_window()
    
    # # Funkcja logowania
    # def login():
    #     try:
    #         WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CLASS_NAME, 'mat-primary-button'))).click()
    #         load_dotenv()
    #         driver.find_element(By.ID, 'username').send_keys(os.getenv('CARELINK_USERNAME'))
    #         driver.find_element(By.ID, 'password').send_keys(os.getenv('CARELINK_PASSWORD'))
    #         driver.find_element(By.CSS_SELECTOR, 'input[name="actionButton"]').click()
    #     except Exception as e:
    #         print("Błąd logowania:", e)
    #         driver.quit()
    
    # Funkcja logowania (dotyczy GUI)
    def login():
        try:
            WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CLASS_NAME, 'mat-primary-button'))).click()
            driver.find_element(By.ID, 'username').send_keys(username)
            driver.find_element(By.ID, 'password').send_keys(password)
            driver.find_element(By.CSS_SELECTOR, 'input[name="actionButton"]').click()
        except Exception as e:
            print("Błąd logowania:", e)
            driver.quit()
    
    # Wybór pacjenta
    def find_and_click_patient(driver, patient_surname, patient_name):
        driver.get('https://carelink.medtronic.eu/clinic/patients')
        patient_input = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.ID, 'patient-users-search')))
        patient_input.send_keys(patient_surname)
        patients_table = driver.find_element(By.ID, 'tbl-patient-list')
        time.sleep(1)
        patients_table_rows = patients_table.find_elements(By.XPATH, '//*[@role="row"]')
        patients_table_names = patients_table.find_elements(By.XPATH, '//mat-row/mat-cell[3]')
        if len(patients_table_rows) > 2:
            for idx, table_name in enumerate(patients_table_names):
                if patient_name.strip().lower() == table_name.text.strip().lower():
                    table_name.click()
                    break
        if len(patients_table_rows) > 1:
            patients_table_rows[1].click()
        else:
            print("Nie znaleziono pacjenta.")
            return
    
    # Wybór zakresu lat w kalendarzu
    def set_calendar(driver, target_year):
        WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, '//button[@aria-label="Choose month and year"]'))).click()
        max_year_search, search_attempts = 1, 0  # Liczba lat do przeszukania i licznik prób
        while search_attempts < max_year_search:
            displayed_year = int(WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, '//button[@aria-label="Choose date"]'))).text[:4])
            if displayed_year > target_year:
                WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, '//button[@aria-label="Previous 24 years"]'))).click()
                search_attempts += 1
            else:
                break
    
    # Wybór odpowiedniego roku w kalendarzu
    def select_year(driver, target_year):
        for button in driver.find_elements(By.CSS_SELECTOR, "button.mat-calendar-body-cell"):
            if int(button.get_attribute("aria-label")) == target_year:
                if button.get_attribute("aria-disabled") != "true":
                    button.click()
                    return target_year
                else:
                    target_year += 1
        return None
    
    # Wybór odpowiedniego miesiąca w kalendarzu
    def select_month(driver, target_month, month_map, start_year, target_year):
        month_range = range(target_month, 13) if target_year == start_year else range(1, 13)
        for month in month_range:
            for button in driver.find_elements(By.CSS_SELECTOR, "button.mat-calendar-body-cell"):
                month_text = button.get_attribute("aria-label").split()[0][:3].upper()
                month_num = month_map.get(month_text)
                if month_num == month and button.get_attribute("aria-disabled") != "true":
                    button.click()
                    return month
        return None
    
    # Wybór odpowiedniego dnia w kalendarzu
    def select_day(driver, target_day, target_month, end_date):
        last_available_day = None
        is_end_month = (target_month == end_date.month)
    
        for button in driver.find_elements(By.CSS_SELECTOR, "button.mat-calendar-body-cell"):
            if button.get_attribute("aria-disabled") == "true":
                continue  # Pomiń wyłączone dni
    
            day_label = int((button.get_attribute("aria-label")).split()[1].replace(",", ""))
    
            if is_end_month:
                if day_label == target_day:
                    button.click()
                    return day_label
                elif day_label < target_day:
                    last_available_day = button
    
            elif day_label >= target_day:
                button.click()
                return day_label
    
        if last_available_day:
            last_available_day.click()
            return int((last_available_day.get_attribute("aria-label")).split()[1].replace(",", ""))
    
        return None  # Jeśli nie znaleziono żadnego pasującego dnia
    
    # Wybór pełnej daty w kalendarzu
    def select_date(driver, start_year, target_year, target_month, target_day, end_date):
        month_map = {"STY": 1, "LUT": 2, "MAR": 3, "KWI": 4, "MAJ": 5, "CZE": 6,
                    "LIP": 7, "SIE": 8, "WRZ": 9, "PAŹ": 10, "LIS": 11, "GRU": 12}
    
        selected_year = select_year(driver, target_year)
        if not selected_year:
            print("Nie znaleziono dostępnego roku.")
            driver.quit()
            sys.exit()
    
        selected_month = select_month(driver, target_month, month_map, start_year, target_year)
        if not selected_month:
            print("Nie znaleziono dostępnego miesiąca.")
            driver.quit()
            sys.exit()
    
        selected_day = select_day(driver, target_day, target_month, end_date)
        if not selected_day:
            print("Nie znaleziono dostępnego dnia.")
            driver.quit()
            sys.exit()
    
        # Zwracamy pełną wybraną datę jako obiekt datetime
        return datetime(selected_year, selected_month, selected_day)
    
    # Wybierz przycisk "Zastosuj" oraz pobierz CSV
    def click_element(driver, element_id, timeout=10):
        # Kliknij element po ID, gdy będzie klikalny
        element = WebDriverWait(driver, timeout).until(EC.element_to_be_clickable((By.ID, element_id)))
        element.click()
    
    # Kolejka do komunikacji między wątkiem przetwarzania a GUI
    gui_queue = queue.Queue()
    
    # Funkcja tworząca GUI z paskami postępu
    def create_progress_window():
        # Główne okno
        progress_window = Tk()
        progress_window.title("Postęp pobierania danych z Carelink")
    
        # Etykiety informacyjne
        patient_label_var = StringVar()
        patient_label = Label(progress_window, textvariable=patient_label_var)
        patient_label.pack(padx=10, pady=10)
    
        # Pasek postępu dla pacjentów
        patient_progress = ttk.Progressbar(progress_window, orient="horizontal", length=300, mode="determinate")
        patient_progress.pack(padx=10, pady=10)
    
        # Pasek postępu dla konkretnego pacjenta
        individual_progress = ttk.Progressbar(progress_window, orient="horizontal", length=300, mode="determinate")
        individual_progress.pack(padx=10, pady=10)
    
        # Etykieta informacyjna
        individual_label_var = StringVar()
        individual_label = Label(progress_window, textvariable=individual_label_var)
        individual_label.pack(padx=10, pady=10)
    
        # Wyśrodkowanie okna
        progress_window.update_idletasks()
        width, height = progress_window.winfo_width(), progress_window.winfo_height()
        x = (progress_window.winfo_screenwidth() - width) // 2
        y = (progress_window.winfo_screenheight() - height) // 2
        progress_window.geometry(f"{width}x{height}+{x}+{y}")
    
        return progress_window, patient_progress, individual_progress, patient_label_var, individual_label_var
    
    # Inicjalizacja okna z paskami postępu
    progress_window, patient_progress, individual_progress, patient_label_var, individual_label_var = create_progress_window()
    
    # Funkcja aktualizacji GUI na podstawie komunikatów z kolejki
    def update_gui():
        try:
            while not gui_queue.empty():
                msg_type, value = gui_queue.get_nowait()
                if msg_type == "update_patient_label":
                    patient_label_var.set(value)
                elif msg_type == "update_patient_progress":
                    patient_progress["value"] = value
                elif msg_type == "update_individual_progress":
                    individual_progress["value"] = value
                elif msg_type == "update_individual_label":
                    individual_label_var.set(value)
                elif msg_type == "done":
                    progress_window.destroy()
                elif msg_type == "error":
                    print("Błąd podczas przetwarzania:", value)
                    progress_window.destroy()
            progress_window.after(100, update_gui)
        except Exception as e:
            print("Błąd aktualizacji GUI:", e)
    
    # Główna funkcja przetwarzania
    def process_patients(df, driver):
        try:
            for patient_index, row in df.iterrows():
                gui_queue.put(("update_patient_label", ""))
                gui_queue.put(("update_individual_label", ""))
                gui_queue.put(("update_patient_progress", 0))
                gui_queue.put(("update_individual_progress", 0))
                
                patient_name, patient_surname = row['Imię'], row['Nazwisko']
                gui_queue.put(("update_patient_label", f"Przetwarzanie pacjenta: {patient_name} {patient_surname} ({patient_index+1}/{len(df)})"))
    
                start_date = pd.to_datetime(row['początek ciąży']).date()
                start_year, start_month, start_day = start_date.year, start_date.month, start_date.day
                end_date = pd.to_datetime(row['Data porodu']).date()
                find_and_click_patient(driver, patient_surname, patient_name)
                WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.ID, 'pd-reports'))).click()
                WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.ID, 'r-reports-days-90'))).click()
                WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, '//*[@id="date-range-button"]'))).click()
                target_year, target_month, target_day = start_year, start_month, start_day
                set_calendar(driver, target_year)
                
                # Ustawienie kalendarza i wybór daty
                selected_date = select_date(driver, start_year, target_year, target_month, target_day, end_date)
    
                # Obliczenie różnicy w dniach między wybraną datą a datą końca porodu oraz liczba 90-dniowych okresów
                days_difference = (end_date - selected_date.date()).days
                ninety_day_periods = min(4, max(1, days_difference // 90 + 1))
    
                # Ustal drugą datę do zaznaczenia w kalendarzu
                current_highlight_date = selected_date + timedelta(days=90)
    
                for i in range(ninety_day_periods):
    
                    # Ustawienia szczegółowe dla konkretnej pacjentki
                    gui_queue.put(("update_individual_label", f"Postęp dla {patient_name} {patient_surname}: okres {i + 1} z {ninety_day_periods}"))
    
                    # Sprawdź, czy to ostatnia iteracja – jeśli tak, ustaw datę docelową jako end_date
                    target_date = end_date if i == ninety_day_periods - 1 else current_highlight_date
                    target_year, target_month, target_day = target_date.year, target_date.month, target_date.day
                    set_calendar(driver, target_year)
                    selected_date = select_date(driver, start_year, target_year, target_month, target_day, end_date)
    
                    # Kliknij przycisk 'zastosuj'
                    click_element(driver, 'date-range-apply')
    
                    # Kliknij przycisk pobierania pliku CSV po załadowaniu strony
                    click_element(driver, 'r-button-data-export-csv', timeout=20)
                    time.sleep(12)
    
                    # Sprawdź, czy to była ostatnia iteracja
                    if i == ninety_day_periods - 1:
                        # Aktualizacja paska postępu dla pacjenta
                        gui_queue.put(("update_individual_progress", (i + 1)/ninety_day_periods))
                        gui_queue.put(("update_patient_progress", (patient_index + 1)/len(df)))
                        break  # Przerwij pętlę po ostatniej iteracji
                    
                    WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, '//*[@id="date-range-button"]'))).click()
                    set_calendar(driver, target_year)
                    selected_date = select_date(driver, start_year, target_year, target_month, target_day, end_date)
    
                    # Aktualizuj current_highlight_date o 90 dni
                    current_highlight_date = selected_date + timedelta(days=90)
    
                    # Aktualizacja paska dla konkretnego okresu pacjentki
                    gui_queue.put(("update_individual_progress", (i + 1)/ninety_day_periods))
    
            # Sygnał zakończenia
            gui_queue.put(("done", None))
    
        except Exception as e:
            gui_queue.put(("error", str(e)))
    
    # Funkcja uruchamiająca Selenium w osobnym wątku
    def run_selenium_in_thread():
        threading.Thread(target=process_patients, args=(df, driver), daemon=True).start()
    
    # Uruchom główne funkcje
    try: 
        login()
        run_selenium_in_thread()
        update_gui()
        progress_window.mainloop()
    
    except Exception as e:
        print(f"Błąd podczas przetwarzania: {e}")
    finally:
        # Zmień opcje Chrome na domyślny folder pobierania
        chrome_options = Options()
        # chrome_options.add_argument("--headless")  # Uruchomienie w tle
        chrome_options.add_experimental_option("prefs", {"download.default_directory": downloads_folder})
    
        # Utwórz nowy driver z zaktualizowanymi opcjami i zamknij stary driver
        driver.quit()  # Zamknij poprzednią sesję
        driver = webdriver.Chrome(service=service, options=chrome_options)
        driver.quit()
RodionGork
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 47
4

Chyba zrob przykład minimałny z paskiem.

lion137
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 5023
0

A jakby użył https://github.com/tqdm/tqdm ?

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.