Back to Blog
Python

Python Selenium File Upload Download and Screenshots

python selenium file upload download and screenshots: Learn how to automate file uploads, manage downloads, and capture screenshots with Python Selenium WebDriver, inc...

seleniumpythonweb automationfile uploadfile downloadscreenshots
Illustration of a Selenium WebDriver automating file upload, download, and screenshot capture in a browser.

Automating file interactions is a common requirement when building end-to-end tests with python selenium file upload download and screenshots. Selenium WebDriver provides direct methods for uploading files, but downloads and screenshots require careful configuration and waiting logic to behave reliably across browsers and environments.

Uploading Files with Selenium's send_keys

File uploads in Selenium are handled through the send_keys method on an <input type="file"> element. Unlike manual interaction, Selenium does not need to open the native file picker dialog. Instead, you directly set the file path on the input element.

from selenium import webdriver from selenium.webdriver.common.by import By driver = webdriver.Chrome() driver.get("https://example.com/upload") file_input = driver.find_element(By.CSS_SELECTOR, "input[type='file']") file_input.send_keys("/path/to/your/file.pdf") # Submit the form or trigger the upload via JavaScript if needed driver.find_element(By.ID, "submit").click()

This works for both single and multiple file inputs. For multiple files, you can pass a list of paths separated by newlines, or use send_keys with a tuple if the input supports multiple.

file_input.send_keys("/path/to/file1.txt\n/path/to/file2.txt")

The key constraint is that the element must be an <input> with type="file". If the upload widget is a custom JavaScript component that hides the native input, you may need to interact with the hidden input directly. In that case, ensure the element is present in the DOM, even if it is not visible. Selenium's send_keys works on hidden inputs as long as they are not disabled.

Configuring the Browser for Automatic Downloads

Unlike uploads, downloads are not handled by a single Selenium method. You must configure the browser to save files to a known directory without prompting, and then monitor that directory for the file to appear.

For Chrome, use add_experimental_option to set download preferences:

from selenium import webdriver options = webdriver.ChromeOptions() prefs = { "download.default_directory": "/path/to/downloads", "download.prompt_for_download": False, "download.directory_upgrade": True, "safebrowsing.enabled": True } options.add_experimental_option("prefs", prefs) driver = webdriver.Chrome(options=options)

For Firefox, use set_preference:

from selenium import webdriver options = webdriver.FirefoxOptions() options.set_preference("browser.download.folderList", 2) options.set_preference("browser.download.dir", "/path/to/downloads") options.set_preference("browser.download.useDownloadDir", True) options.set_preference("browser.helperApps.neverAsk.saveToDisk", "application/pdf,text/plain") options.set_preference("pdfjs.disabled", True) # for PDFs driver = webdriver.Firefox(options=options)

These preferences tell the browser to automatically save files to a specific folder and suppress the download prompt. The MIME types in neverAsk.saveToDisk should match the files you expect to download. You may need to adjust them based on your test data.

Waiting for Downloads to Complete

After triggering a download, you cannot assume the file exists immediately. The browser downloads asynchronously, and you need to wait until the file is fully written. A simple time.sleep is unreliable and slows down tests. Instead, poll the file system for the expected file.

A common approach is to use WebDriverWait combined with a custom condition that checks for the file's existence and stability:

import os import time from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC def wait_for_download(download_dir, filename, timeout=30): file_path = os.path.join(download_dir, filename) def file_ready(_): if not os.path.exists(file_path): return False # Check that the file size is stable (i.e., not still growing) size1 = os.path.getsize(file_path) time.sleep(0.5) size2 = os.path.getsize(file_path) return size1 == size2 and size1 > 0 WebDriverWait(driver, timeout).until(file_ready) return file_path

This function polls every 0.5 seconds until the file exists and its size stops changing. It handles both the appearance of the file and the completion of the write. For large files, you may need to increase the timeout.

If you are unsure of the exact filename, you can watch the directory for any new file matching a pattern:

def wait_for_any_download(download_dir, timeout=30): before = set(os.listdir(download_dir)) def new_file_appeared(_): after = set(os.listdir(download_dir)) return after - before new_files = WebDriverWait(driver, timeout).until(new_file_appeared) return os.path.join(download_dir, list(new_files)[0])

Note that some browsers append a .crdownload or .part extension while downloading. You may need to filter those out or wait for the final extension to appear.

Taking Element and Full-Page Screenshots

Screenshots are essential for visual regression testing or for capturing evidence of a state. Selenium provides two primary methods: save_screenshot for the full viewport, and element.screenshot for a specific element.

# Full page screenshot (viewport only) driver.save_screenshot("full_page.png") # Element screenshot element = driver.find_element(By.ID, "result") element.screenshot("element.png")

For full-page screenshots that include content below the fold, you need to adjust the window size or use a scrolling strategy. One common technique is to resize the browser window to the full document height before capturing:

def full_page_screenshot(driver, path): original_size = driver.get_window_size() required_width = driver.execute_script("return document.body.parentNode.scrollWidth") required_height = driver.execute_script("return document.body.parentNode.scrollHeight") driver.set_window_size(required_width, required_height) driver.save_screenshot(path) driver.set_window_size(original_size["width"], original_size["height"])

This works for most static pages, but dynamic content that loads on scroll may require additional handling. For such cases, consider using a library like selenium-screen or a headless browser with a larger viewport.

Handling Headless Mode and Browser Preferences

When running tests in headless mode, downloads and screenshots behave differently. Headless Chrome and Firefox still support downloads, but you must ensure the download directory is set correctly and that the browser does not prompt for confirmation. The preferences shown earlier work in headless mode, but you may need to add --headless=new for Chrome and -headless for Firefox.

options = webdriver.ChromeOptions() options.add_argument("--headless=new") # ... download preferences

For screenshots, headless mode often has a default viewport size that may not match your desktop browser. You can set the window size explicitly:

options.add_argument("--window-size=1920,1080")

This ensures that your screenshots have consistent dimensions. Note that in headless mode, set_window_size may not work as expected, so it is better to set the size via command-line arguments.

Common Pitfalls and Runtime Considerations

Several issues frequently arise when combining upload, download, and screenshot operations in a single Selenium script.

Hidden file inputs: If the upload button is a custom widget, the actual <input type="file"> may be hidden. send_keys works on hidden inputs, but you must ensure the element is not disabled. If the input is outside the viewport, Selenium may still interact with it, but some browsers require the element to be visible. In such cases, use JavaScript to remove the display:none style or use element.send_keys directly without clicking.

Download directory permissions: The browser process must have write access to the download directory. Running tests as a non-privileged user can cause silent failures where the file is not saved. Always verify that the directory exists and is writable before starting the test.

Screenshot timing: Screenshots capture the current state of the page. If you need to capture a state after a download or upload, wait for the page to update using explicit waits on expected conditions, not just time.sleep. For example, after clicking an upload button, wait for a success message to appear before taking a screenshot.

Concurrency and isolation: When running tests in parallel, each test should use its own download directory and screenshot filename to avoid conflicts. Use unique paths based on test names or timestamps.

Browser-specific behavior: Chrome and Firefox have different download preference keys. If your test suite runs on multiple browsers, abstract the download configuration behind a factory method that returns the appropriate options object for each browser.

Resource cleanup: Always quit the driver in a finally block or use a context manager to avoid leaving browser processes running, especially when tests fail. This is also important for releasing file locks on downloaded files.

try: # test steps except Exception: driver.save_screenshot("failure.png") raise finally: driver.quit()

By handling these runtime details, you can build reliable automation scripts that consistently handle file uploads, downloads, and screenshots across different environments.

python selenium file upload download and screenshots: Practi | RYUSLOG DEV