def click_internal_link(self): links = self.gather_internal_links() if not links or len(links) < 10: return # sort by link length (try to prioritize article links) links.sort(key=lambda item: (-len(item[0]), item[0])) # take top ten links = links[:10] link_href, link_el = random.choice(links) self.logger.info("Clicking on %s", link_href) try: curl = self.driver.current_url cwindows = self.driver.window_handles try: link_el.click() except (ElementClickInterceptedException, ElementNotInteractableException, ElementNotVisibleException): self.driver.execute_script("arguments[0].click()", link_el) try: WebDriverWait(self.driver, 15).until( EC.any_of(EC.url_changes(curl), EC.new_window_is_opened(cwindows))) except TimeoutException: pass except WebDriverException as e: self.logger.error("Failed to visit link (%s): %s", type(e).__name__, e.msg) else: # TODO wait for the page to actually load first self.scroll_page()
def any_of(*expected_conditions): """ An expectation that any of multiple expected conditions is true. Equivalent to a logical 'OR'. Returns results of the first matching condition, or False if none do. """ # If the installed version of Selenium WebDriver is >= 4, # then just directly use its implementation of this function. if is_web_driver_version_ge_4(): return EC.any_of(*expected_conditions) # Otherwise, use the (snapshot) copy of it from the Selenium 4 beta, below. def any_of_condition(driver): for expected_condition in expected_conditions: try: result = expected_condition(driver) if result: return result except WebDriverException: pass return False return any_of_condition
def _await_element_to_enable(self, tag: Tag, *pairs: tuple[Param, Condition, str]) -> WebElement: WebDriverWait(self._driver, 5).until(any_of(*[element_to_be_clickable(elem) for elem in self._driver.find_elements(By.XPATH, create(tag, *pairs))])) return self._find_visible_enabled(tag, *pairs)
def test_any_of_false(driver, pages): pages.load("simpleTest.html") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.1).until(EC.any_of( EC.title_is("Nope"), EC.title_is("Still Nope")))
def test_any_of_true(driver, pages): pages.load("simpleTest.html") WebDriverWait(driver, 0.1).until(EC.any_of( EC.title_is("Nope"), EC.title_is("Hello WebDriver")))
def get_dsid_cookie(url, username, password, show_browser=False): if "://" not in url: url = f"https://{url}" info("Creating web driver...") options = Options() if not show_browser: options.headless = True driver = webdriver.Firefox(options=options) info("Loading login url...") driver.get(url) info("Waiting for username field...") username_input = WebDriverWait(driver, timeout=30).until( expected_conditions.visibility_of_element_located( (By.ID, USERNAME_FIELD_ID))) info("Username field loaded.") info("Checking if connection is secure...") current_url = driver.current_url if not current_url.startswith("https"): driver.quit() raise RuntimeError(f"Connection not secure: {current_url!r}") info("Finding password field...") password_input = driver.find_element(By.ID, PASSWORD_FIELD_ID) if password_input.get_attribute("type") != "password": info( f"Password input type is {password_input.get_attribute('type')} instead of " f"'password': {password_input.get_attribute('outerHTML')}") driver.quit() RuntimeError( f"Input with id {PASSWORD_FIELD_ID!r} is not a password input.") info("Password field found.") info("Entering credentials...") username_input.send_keys(username) password_input.send_keys(password) info("Logging in...") username_input.submit() info("Waiting for Send Push button...") wait_result = WebDriverWait(driver, timeout=30).until( expected_conditions.any_of( expected_conditions.visibility_of_element_located( (By.XPATH, SEND_PUSH_BTN_XPATH)), expected_conditions.visibility_of_element_located( (By.CSS_SELECTOR, LOGIN_FAILED_SELECTOR)), )) try: send_push_btn = driver.find_element(By.XPATH, SEND_PUSH_BTN_XPATH) except NoSuchElementException: info("Login failed. Error message element: ", wait_result.get_attribute("outerHTML")) error_message = wait_result.text driver.quit() raise RuntimeError(f"Login Failed: {error_message}") info("Send Push button found.") info("Sending push notification...") send_push_btn.click() info("Waiting for redirect...") WebDriverWait(driver, timeout=120).until(expected_conditions.url_contains(url)) info("Redirected.") info(f"Getting {COOKIE_ID!r} cookie...") dsid_cookie = driver.get_cookie(COOKIE_ID) if dsid_cookie: info(f"Successfully got {COOKIE_ID!r} cookie.") driver.quit() return dsid_cookie["value"] info( f"Cookie {COOKIE_ID!r} not found. Looking for further login button...") login_btn = driver.find_element(By.CSS_SELECTOR, SECONDARY_LOGIN_BTN_SELECTOR) if (login_btn.get_attribute("type") != "submit" or "log in" not in login_btn.get_attribute("value").lower()): info(f"No further login button found.") driver.quit() raise RuntimeError( f"Login successful but could not find cookie: {COOKIE_ID}") if login_btn.get_attribute("disabled"): info(f"Found disabled login button, looking for checkbox...") checkbox = driver.find_element(By.CSS_SELECTOR, SECONDARY_CHECKBOX_SELECTOR) if checkbox.get_attribute("type") != "checkbox": info(f"No checkbox found.") driver.quit() raise RuntimeError( f"Initial login successful but could not find cookie: {COOKIE_ID}" ) info(f"Checkbox found, clicking...") checkbox.click() info(f"Waiting for login button...") login_btn = WebDriverWait(driver, timeout=8).until( expected_conditions.element_to_be_clickable( (By.CSS_SELECTOR, SECONDARY_LOGIN_BTN_SELECTOR))) current_url = driver.current_url info(f"Clicking login button...") login_btn.click() info("Waiting for redirect...") WebDriverWait(driver, timeout=30).until( expected_conditions.url_changes(current_url)) info("Redirected.") dsid_cookie = driver.get_cookie(COOKIE_ID) if not dsid_cookie: info("Still no cookie found.") driver.quit() raise RuntimeError( f"Login successful but could not find cookie: {COOKIE_ID}") info(f"Successfully got {COOKIE_ID!r} cookie.") driver.quit() return dsid_cookie["value"]