No history yet

Advanced Selenium Techniques

Waiting for the Web

Websites aren't static pages anymore. When you click a button or scroll down, content often appears without the entire page reloading. This is thanks to technologies like AJAX, which fetch data in the background. For a web automation script, this poses a challenge. If your script tries to find an element that hasn't loaded yet, it will fail with a NoSuchElementException.

Simply telling your script to pause for a few seconds is a fragile solution. What if the network is slow? What if it's fast? You either wait too long, slowing down your script, or not long enough, causing it to fail. The proper solution is to wait intelligently.

Selenium provides tools called "waits" to handle this. The best practice is to use explicit waits. An explicit wait tells the WebDriver to pause and periodically check for a specific condition to be met before continuing. If the condition is met, the script moves on immediately. If it isn't met within a set timeout period, it throws an exception.

This is managed with the WebDriverWait class, combined with ExpectedConditions. You can wait for an element to be visible, clickable, or for its text to change. It’s a precise and efficient way to synchronize your script with the dynamic state of the web page.

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# Assume 'driver' is an initialized WebDriver instance
driver.get("https://example.com/dynamic_page")

try:
    # Wait up to 10 seconds until the element with id 'ajax-content' is visible
    wait = WebDriverWait(driver, 10)
    element = wait.until(
        EC.visibility_of_element_located((By.ID, "ajax-content"))
    )
    # Now that we know the element is visible, we can interact with it
    print("Element is visible!")
finally:
    driver.quit()

Advanced User Actions

Automating web browsers goes beyond just clicking buttons and typing text. Many user interfaces require more complex gestures like hovering over a menu to reveal options, or dragging an item from one list to another. Selenium handles these with the Actions class.

The Actions class allows you to build a chain of user interactions. You can queue up a sequence of events—like moving the mouse to an element, clicking and holding, moving again, and then releasing the mouse button. Once the sequence is defined, you call the perform() method to execute all the actions in order.

Let's look at how to perform a drag-and-drop operation. This is a classic example of a complex user action.

from selenium.webdriver.common.action_chains import ActionChains

# Assume 'driver' is an initialized WebDriver instance

source_element = driver.find_element(By.ID, 'draggable')
target_element = driver.find_element(By.ID, 'droptarget')

# Create an ActionChains instance
actions = ActionChains(driver)

# Build the drag-and-drop chain and perform it
actions.drag_and_drop(source_element, target_element).perform()

print("Drag and drop complete.")

Similarly, hovering the mouse over an element to reveal a hidden menu is a common task. The moveToElement() method is perfect for this.

from selenium.webdriver.common.action_chains import ActionChains

# Find the menu trigger and the hidden link
menu_trigger = driver.find_element(By.ID, 'main-menu')
submenu_link = driver.find_element(By.ID, 'submenu-item-1')

actions = ActionChains(driver)

# Hover over the main menu, then move to and click the submenu item
actions.move_to_element(menu_trigger).click(submenu_link).perform()

print("Clicked on submenu item.")

Managing Browser State

Sometimes your automation needs to manage the state of the browser itself. This includes handling cookies, switching between different windows or tabs, and working with frames.

Cookies are small pieces of data that websites use to remember information about you, like whether you're logged in. Selenium allows you to interact with cookies to simulate different user sessions. You can add a cookie to log in without going through the UI, or delete all cookies to log out and start fresh.

# Add a cookie to the current session
# This is useful for pre-authenticating a session
cookie = {'name': 'session_id', 'value': '12345'}
driver.add_cookie(cookie)

# Get all cookies
all_cookies = driver.get_cookies()
print(all_cookies)

# Delete all cookies for a clean slate
driver.delete_all_cookies()
print("Cookies cleared.")

Modern web applications also frequently open new tabs or popup windows. Your WebDriver instance initially only has control over the window it started in. To interact with a new window, you must explicitly switch control to it. WebDriver maintains a list of window "handles," which are unique identifiers for each open window or tab.

You can get the list of all handles and then switch to the one you need.

# Get the handle of the original window
original_window = driver.current_window_handle

# Assume clicking a link opens a new tab
driver.find_element(By.LINK_TEXT, 'Open New Tab').click()

# Wait for the new window or tab
wait.until(EC.number_of_windows_to_be(2))

# Loop through every window handle
for window_handle in driver.window_handles:
    if window_handle != original_window:
        driver.switch_to.window(window_handle)
        break

# Now the driver is focused on the new tab
print(f"Switched to new window with title: {driver.title}")

# To switch back to the original window
driver.switch_to.window(original_window)

Waits are essential in Selenium to handle dynamic content and avoid errors related to elements not being ready for interaction.

With these advanced techniques, you can build much more robust and capable automation scripts that can handle the complexities of modern web applications.

Time to test your knowledge.

Quiz Questions 1/6

Why is using an explicit wait considered a best practice in Selenium for handling dynamic content?

Quiz Questions 2/6

Which of the following is the final method call required to execute a sequence of actions built using the Actions class?