I'm new to Python and learning test automation. I’ve written a UI test using Pylenium that goes through an educational blog site and does the following: Opens each category from a dropdown Checks the left-side menu and collects all tabs For each tab, it: Opens the tab Checks the tab name and the number of courses shown in parentheses Iterates through paginated content and counts the actual number of courses on each page Compares the actual total count across all pages to the expected count from the tab label The test works correctly, but it takes over 2 minutes (0:02:14) to complete. My main question is: How can I speed this up? Is it possible to optimize the structure. page url: https://intellipaat.com/blog/ai/ from selenium.webdriver.support.select import Select from selenium.webdriver.common.by import By from loguru import logger from pylenium.driver import Pylenium class Blog: def __init__(self, py: Pylenium): self.py = py self.py.visit("https://intellipaat.com/blog/ai/") def getOptions(self): self.py.wait().until(lambda _: self.py.get("#catdropdown")) dropdown = Select(self.py.get("#catdropdown").webelement) options = [(opt.text.strip(), opt.get_attribute("data")) for opt in dropdown.options] logger.info(f"Dropdown options fetched: {[opt[0] for opt in options]}") return options def openeCategory(self, category_name, category_url): logger.info(f" Checking category: {category_name} → {category_url}") self.py.visit(category_url) self.py.wait().until(lambda _: self.py.getx('//*[@id="tutorial-single-left"]/div[2]').should().be_visible()) class TabContent: def __init__(self, py: Pylenium): self.py = py self.tabContent = self.get_tabContent() self.active_pane = self.get_active_pane() self.pages_raw = self.get_pages_raw() self.pages_filtered = self.get_pages_filtered() def get_tabContent(self): return self.py.get("#cat-tabContent") def get_active_pane(self): return self.tabContent.get(".tab-pane.active") def get_pages_raw(self): pagination = self.active_pane.get(".pagination") pages = pagination.webelement.find_elements(By.CSS_SELECTOR,".page-numbers") #py.find is so slow for some reason ;-; return pages def get_pages_filtered(self): return [el for el in self.pages_raw if el.text.strip() not in ["NEXT »", "« Previous"]] def get_page_count(self): if len(self.pages_filtered) != 0: return int(self.pages_filtered[-1].text.strip()) return 0 def go_to_next_page(self): next_button = next( (el for el in self.pages_raw if "next" in el.get_attribute("class").split() and "page-numbers" in el.get_attribute("class").split()),None) try: if next_button: next_button.click() else: print("Next button not found!") except Exception as e: print(f"Couldn't click next button: {e}") class page: def __init__(self, py: Pylenium, active_pane): self.py = py self.active_pane = active_pane self.CurseCount = self.get_pageContentCount() logger.info(f"Detected {self.CurseCount} courses on current page.") def get_pageContentCount(self): return len(self.active_pane.get(".row").webelement.find_elements(By.CSS_SELECTOR,".col-lg-4.col-md-6")) class LeftMenu: def __init__(self, py: Pylenium): self.py = py self.name = self.getName() self.tabs = self.getTabs() logger.info(f"Left menu name: {self.name} | Tabs found: {len(self.tabs)}") def getName(self): cat_left_top = self.py.getx('//*[@id="tutorial-single-left"]/div[2]') return cat_left_top.getx('.//h1').text().strip() def getTabs(self): cat_left_top = self.py.getx('//*[@id="tutorial-single-left"]/div[2]') return cat_left_top.findx('.//div/a') class Tabs: def __init__(self, py: Pylenium, tabs_elements): self.py = py self.tabs_elements = tabs_elements self.count = self.get_tab_count() def get_tab_count(self): return len(self.tabs_elements) def openTab(self, tabId): logger.info(f"Opening tab index: {tabId}") return self.tabs_elements[tabId].click() class Tab: def __init__(self, py: Pylenium, tab_element): self.py = py self.tab_element = tab_element self.name = self.get_name() self.count_tag = self.get_count_of_elements_tag() logger.info(f"Tab initialized → {self.name}: {self.count_tag} items") def get_name(self): return self.tab_element.text().split("(")[0].strip() def get_count_of_elements_tag(self): return int(self.tab_element.getx('.//span').text().strip().replace("(", "").replace(")", "")) def test_blog(py: Pylenium): blog = Blog(py) options = blog.getOptions() for category_name, category_url in options: blog.openeCategory(category_name, category_url) left_menu = blog.LeftMenu(py) Remembered_left_menu_name = left_menu.name left_menu_tabs_elements = left_menu.getTabs() RememberedTabss = left_menu.Tabs(py, left_menu_tabs_elements) RememberedTabs = [RememberedTabss.Tab(py, el) for el in left_menu_tabs_elements] for i in range(len(RememberedTabs)): logger.info(f"Opening Tab {i}: {RememberedTabs.name}") left_menu = blog.LeftMenu(py) assert Remembered_left_menu_name == left_menu.name tabs = left_menu.Tabs(py, left_menu.getTabs()) tab = tabs.Tab(py, tabs.tabs_elements) tabcontent = blog.TabContent(py) pagescount = tabcontent.get_page_count() logger.info(f" Pagecount: {pagescount} on tab '{tab.name}'") if pagescount > 0: numberofcurses = 0 for pagenumber in range(pagescount): logger.info(f"➡️ Loading page {pagenumber + 1}/{pagescount}...") tabcontent = blog.TabContent(py) page = tabcontent.page(py, tabcontent.active_pane) numberofcurses += page.CurseCount for a in range(len(RememberedTabs)): tabs = left_menu.Tabs(py, left_menu.getTabs()) assert RememberedTabs[a].name == tabs.Tab(py, tabs.tabs_elements[a]).name assert RememberedTabs[a].count_tag == tabs.Tab(py, tabs.tabs_elements[a]).count_tag tabcontent.go_to_next_page() logger.info(f"✅ Total courses found across all pages on tab '{tab.name}': {numberofcurses}") assert numberofcurses == RememberedTabs.count_tag else: logger.warning(f"⚠️ Single page only. Expected: {RememberedTabs.count_tag}, Found: {tabcontent.page(py, tabcontent.active_pane).CurseCount}") for a in range(len(RememberedTabs)): tabs = left_menu.Tabs(py, left_menu.getTabs()) assert RememberedTabs[a].name == tabs.Tab(py, tabs.tabs_elements[a]).name assert RememberedTabs[a].count_tag == tabs.Tab(py, tabs.tabs_elements[a]).count_tag if (len(RememberedTabs) - 1) > i: tabs.openTab(i + 1) Opens the blog URL and fetches all category options from the dropdown menu. Iterates through each category: Navigates to the category URL. Reads the left-side tab menu, including tab names and the course count shown next to them. For each tab inside the category: Opens the tab. Calculates how many pages of content it contains using the pagination component. Visits each page and counts the number of visible course blocks. Sums the total count and compares it against the expected count shown in the tab label (e.g., "Courses (15)"). Also re-validates tab names and course counts after each page change to ensure DOM consistency. Asserts that: The total number of courses found across pages matches the expected count. The tab labels and counts remain stable between navigations. The test works correctly, but it takes over 2 minutes (0:02:14) to complete. Continue reading...