Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use the method that matches what the tab contains. If Selenium is displaying an HTML report and you want to create a PDF, call Selenium’s print command, decode the returned Base64 data, and write it to a file. If the tab is displaying an existing PDF returned by a server, configure the browser to download PDF responses, preserve the authenticated session, and wait for the completed file. Do not automate Chrome’s or Firefox’s built-in PDF viewer with DOM selectors.

Choose the correct Selenium workflow

A browser tab that looks like a PDF can represent two different things:

What the URL returns Correct approach What you save
HTML, such as an invoice or report page Use Selenium’s print-to-PDF command A PDF rendered by the browser, including the page’s print styles
An existing response with Content-Type: application/pdf Configure a download directory and download the response The server-provided PDF bytes

These paths have different fidelity. Printing reproduces the current rendered page and its @media print rules; downloading preserves the PDF generated by the server. Authentication also differs: a browser download automatically uses the current Selenium session, while a separate HTTP request must reproduce its cookies, authorization headers, redirects, and any anti-bot checks.

Create a PDF from a rendered HTML page

Complete Python example

Selenium’s Python binding returns the print result as Base64-encoded PDF data. Decode it and write the bytes to a deterministic path. Chromium printing in this Selenium example requires headless mode.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
#1 Best Overall
Canon Canoscan Lide 300 Scanner (PDF, AUTOSCAN, Copy, Send)
  • Scanner type: Document
  • Connectivity technology: USB
  • With Auto Scan Mode, the scanner automatically detects what you're scanning
  • Digitize documents and images
from pathlib import Path
import base64

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.print_page_options import PrintOptions
from selenium.webdriver.support.ui import WebDriverWait

url = "https://example.test/report"
out = Path("artifacts/report.pdf")
out.parent.mkdir(parents=True, exist_ok=True)

options = Options()
options.add_argument("--headless=new")
driver = webdriver.Chrome(options=options)

try:
    driver.get(url)

    # Replace this with a selector that proves your report is ready.
    WebDriverWait(driver, 30).until(
        lambda d: d.find_element("css selector", "[data-report-ready]")
    )

    print_options = PrintOptions()
    # Optional: print_options.page_ranges = ["1-3"]
    pdf_b64 = driver.print_page(print_options)
    pdf_bytes = base64.b64decode(pdf_b64)
    if not pdf_bytes:
        raise RuntimeError("Selenium returned an empty print result")
    out.write_bytes(pdf_bytes)
    print(f"Saved {out.resolve()} ({len(pdf_bytes)} bytes)")
finally:
    driver.quit()

Remove the readiness wait only when the page is guaranteed to be complete immediately after navigation. A fixed sleep is less reliable than waiting for a report-specific element, because slow data requests can finish earlier or later on different runs.

Control pages and print appearance

  • Page ranges: assign print_options.page_ranges, for example ["1-3"], when only selected pages are needed.
  • Print CSS: the output follows the browser’s print rendering, so inspect @media print rules when colors, navigation, or layout differ from the screen.
  • Dynamic content: wait for the final table, chart, or report marker before calling print_page. If content is loaded by JavaScript after the marker, wait for a more specific condition.
  • Output folders: create the parent directory before writing and use a unique or cleaned filename in CI so an earlier artifact cannot be mistaken for a new one.

Other Selenium language bindings

JavaScript and Java expose the corresponding print command and PrintOptions APIs. The command is named printPage in JavaScript bindings and is exposed through the PrintsPage interface in Java. The returned value and the Base64 decode/write call are binding-specific; apply the same sequence: navigate, wait for readiness, call the print command, decode the returned PDF data, and write bytes to disk.

Download a PDF that the server already provides

If navigation returns an actual PDF, printing the PDF viewer would not preserve the original file. Configure downloads before opening the URL, then wait for the final file. Keep the browser session alive until the transfer finishes.

Chrome with Python

from pathlib import Path
import time
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

folder = Path("artifacts/pdfs").resolve()
folder.mkdir(parents=True, exist_ok=True)

prefs = {
    "download.default_directory": str(folder),
    "download.prompt_for_download": False,
}
options = Options()
options.add_experimental_option("prefs", prefs)
# In automated runs, make PDF responses download rather than open in the viewer.
options.add_experimental_option("prefs", {
    **prefs,
    "plugins.always_open_pdf_externally": True,
})
# Add --headless=new when running without a display.
# options.add_argument("--headless=new")

driver = webdriver.Chrome(options=options)
try:
    driver.get("https://example.test/files/report.pdf")
    deadline = time.time() + 60
    while time.time() < deadline:
        partials = list(folder.glob("*.crdownload"))
        pdfs = [p for p in folder.glob("*.pdf") if p.stat().st_size > 0]
        if pdfs and not partials:
            print(f"Downloaded {pdfs[0]}")
            break
        time.sleep(0.25)
    else:
        raise TimeoutError("PDF did not finish downloading")
finally:
    driver.quit()

Chrome’s user-facing equivalent is Settings → Privacy and security → Site Settings → Additional content settings → PDF documents → Download PDFs. In automation, set an explicit download directory through the options supported by your Selenium binding and execution environment. The .crdownload file is Chrome’s temporary transfer; do not process it as the final document.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #2
Sale
Brother DS-640 Compact Mobile Document Scanner, (Model: DS640)
  • FAST SPEEDS - Scans color and black and white documents a blazing speed up to 16ppm (1). Color scanning won’t slow you down as the color scan speed is the same as the black and white scan speed.
  • ULTRA COMPACT – At less than 1 foot in length and only about 1. 5lbs in weight you can fit this device virtually anywhere (a bag, a purse, even a pocket).
  • READY WHENEVER YOU ARE – The DS-640 mobile scanner is powered via an included micro USB 3. 0 cable allowing you to use it even where there is no outlet available. Plug it into you PC or laptop and you are ready to scan.
  • WORKS YOUR WAY – Use the Brother free iPrint&Scan desktop app for scanning to multiple “Scan-to” destinations like PC, Network, cloud services, Email and OCR. (2) Supports Windows, Mac and Linux and TWAIN/WIA for PC/ICA for Mac/SANE drivers. (3)
  • OPTIMIZE IMAGES AND TEXT – Automatic color detection/adjustment, image rotation (PC only), bleed through prevention/background removal, text enhancement, color drop to enhance scans. Software suite includes document management and OCR software. (4)

Firefox with Python

from pathlib import Path
from selenium import webdriver
from selenium.webdriver.firefox.options import Options

folder = Path("artifacts/pdfs").resolve()
folder.mkdir(parents=True, exist_ok=True)

options = Options()
options.set_preference("browser.download.folderList", 2)
options.set_preference("browser.download.dir", str(folder))
options.set_preference(
    "browser.helperApps.neverAsk.saveToDisk",
    "application/pdf",
)
# This bypasses the built-in viewer in many Firefox versions.
# Verify the preference against the Firefox version used by your project.
options.set_preference("pdfjs.disabled", True)

driver = webdriver.Firefox(options=options)
try:
    driver.get("https://example.test/files/report.pdf")
    # Poll folder for a nonzero .pdf and wait until any .part file disappears.
finally:
    driver.quit()

The MIME type in browser.helperApps.neverAsk.saveToDisk must match the response’s Content-Type. If the server sends a different type, inspect its response headers and use that value. Firefox uses a .part temporary file while downloading.

Preserve authentication and session state

Download preferences do not log you in. Perform the login with Selenium first, then navigate to the PDF link or URL in the same driver. This carries the browser’s cookies and session state into the request. If a link opens a new tab, switch to that window before checking the download directory.

You can retrieve known PDF bytes with an HTTP client instead of Selenium, but that is equivalent only when you safely transfer every requirement of the browser request: cookies, authorization headers, redirects, and anti-bot protections. When any of those are uncertain, let Selenium perform the download and validate the resulting file.

Wait for and verify the completed file

  1. Clean the destination directory before each run, or generate a unique run directory.
  2. Wait for a final filename with a nonzero size.
  3. Ensure Chrome’s .crdownload or Firefox’s .part temporary files no longer exist.
  4. Read the first five bytes and require the PDF signature %PDF-.
  5. For stronger validation, open the file with a PDF parser and confirm that at least one page can be read.
from pathlib import Path

def assert_pdf(path: Path) -> None:
    if not path.exists() or path.stat().st_size == 0:
        raise AssertionError(f"Missing or empty file: {path}")
    with path.open("rb") as f:
        if f.read(5) != b"%PDF-":
            raise AssertionError(f"Not a PDF: {path}")

For print-to-PDF, perform the same nonempty and signature checks immediately after decoding. A successful Selenium command does not guarantee that the page contained the data you expected.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #3
Plustek PS186 Desktop Document Scanner, with 50-Pages Auto Document Feeder (ADF). for Windows 7/8 / 10/11 (Intel/AMD only)
  • Up to 255 customize favorite scan file setting with "Single Touch" , Support Windows 7/8/10
  • Turn paper documents into searchable, editable files - save scans as searchable PDF files; OCR function included
  • Info Barcode function - automatic categorization of complicate documentation and data with 1D or 2D Barcode page.
  • Intelligent color and image adjustments — Auto Rotate, Crop, Deskew and blank page remove with Plustek Image Processing Technology
  • Easy send scanned files to FTP server or personal NAS (FTP) with PDFs , Jpeg , TIFF or Png format. User can download scanner driver from Plustek website

Print versus download: practical trade-offs

Concern Print-to-PDF Existing-PDF download
Input Rendered HTML Server response identified as a PDF
Fidelity Browser layout and @media print rules Original server-generated bytes
Browser control print_page and print options Download directory and MIME preferences
Authentication Uses the current page session Uses the current session when Selenium performs the download
CI considerations Headless Chromium is required in the documented example Temporary-file polling and browser-specific preferences are required

Troubleshooting Selenium PDF saves

The output is a viewer page, not a PDF

You navigated to an existing PDF and attempted to select text or click viewer controls. Treat it as a download instead: set Chrome or Firefox download preferences before navigation, then monitor the filesystem.

print_page returns an error or empty data

Confirm that the driver is running in the required headless configuration, the page has finished rendering, and the returned string is decoded as Base64 before writing. Check that the decoded byte string is nonempty and begins with %PDF-.

The download never appears

Verify the absolute download directory, ensure it exists and is writable, and confirm that the response is not an HTML login page or an authorization error. Check for a lingering .crdownload or .part file before declaring a timeout.

Firefox still prompts for a location

Set browser.download.folderList, browser.download.dir, and browser.helperApps.neverAsk.saveToDisk before creating the driver. Correct the MIME type if it does not match the server header. Browser preferences are version-sensitive, so verify pdfjs.disabled with the Firefox version used in CI.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #4
Hczrc Portable Scanner, Photo Scanner for A4 Documents, Handheld Scanner for Business, Photo, Picture, Receipts, Books, JPG/PDF Format Selection, UP to 900 DPI, with 16G SD Car
  • Note: No software installation is required. You need 2 AA batteries ( not included) and a memory card ( included) to use it directly. Scan mode: Press and hold "Scan" for 2 seconds to turn on the device, and then press "Scan", the green light is on. The scanner moves to scan the file until the green light turns off automatically (or press the "Scan" key and the green light goes out). The number shown on the display increases by 1 to indicate that the scan is complete.
  • Portable Scanner scans images or pictures quickly: Store JPEG/PDF files within seconds, scan images or pictures quickly, plug and play, no need any software preinstalled. Compatible with Windows XP/7/Vista/Mac OS 10.4 or above version.
  • Lightweight and travel-friendly: Stored in Micro SD card directly, support read data on your computer or phone with USB connected. Powered by 2pcs AA batteries, Compact Design, it is convenient to carry outside.
  • 3 Image Resolution: 3 modes of resolution for your options: 300dpi/600dpi/900dpi, you can save it at the clearest way, picture and document are showed clear as it is. Freely choose your favorite resolution.File Format: JPEG/PDF format is all available, Great storage capacity as it supports 32G Micro SD card(Included 16GB Card),total meet your need for business trip or daily use.
  • Widely Used: It is applicable in bank, insurance business, real estate agency,home, office, library or outdoors. suitable for lawyer, businessmen, students, travelers and amateur archivists. Scan your important files and save them immediately, no struggling in finding a printing shop, keep it confidential.

The saved file is an old report

Clean the folder first or use a unique filename and run directory. A test that merely finds any .pdf can pass on a stale artifact.

The PDF lacks charts or late-loaded rows

Wait for a report-specific readiness condition rather than relying on navigation completion. For print output, inspect the page’s print stylesheet and make sure the content is present in the DOM before invoking the print command.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Performance, reliability, and cost considerations

  • Reuse a logged-in driver only when session isolation is acceptable; otherwise create a fresh profile for each test.
  • Use explicit waits and bounded polling intervals. Long fixed sleeps make fast runs slower while still failing on unusually slow pages.
  • Keep download directories isolated per test worker to avoid filename collisions and false positives.
  • Headless runs need the same browser version and driver compatibility as interactive runs; pin those in CI where reproducibility matters.
  • Printing consumes browser resources because the page is rendered locally. Downloading a server PDF is generally simpler when the original PDF URL is available and authenticated access is straightforward.

Or skip the browser setup

For a one-request capture of a rendered page, ScreenshotNeo provides a website screenshot API and MCP server. It accepts the page URL and can return PNG, JPEG, WebP, or PDF output; its cleanup steps accept cookie or consent banners and remove more than 60 known consent platforms, newsletter popups, and chat widgets before capture.

Example request (see the ScreenshotNeo documentation for output options):

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.test/report -o report.webp

Only clean shots are billed. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and each response identifies the result with X-Page-Verdict and X-Billed headers. An MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

Best Value
Sale
Epson Workforce ES-50 Compact & Lightweight Mobile Document Scanner
  • PORTABLE SCANNER FOR USE ON-THE-GO — The fastest and lightest mobile single-sheet-fed compact document scanner in its class¹
  • QUICK DOCUMENT SCANNING ― This Epson ultra-fast scanner scans a single page as quickly as 5.5 seconds²; Windows and Mac compatible
  • VERSATILE PAPER HANDLING ― Portable scanner scans documents up to 8.5 x 72 in; Also easily digitizes receipts and ID cards to make accounting, bookkeeping, and organizing simpler
  • INTUITIVE, HIGH-SPEED SOFTWARE — Epson ScanSmart Software³ is a smart tool allowing you to easily scan, review, and save; Stay organized easily with the help of this Epson scanner
  • EASY SETUP — USB-powered connect to your computer for quick and simple scanning; No batteries or external power supply required to operate portable document scanner; Standard Connectivity: USB 2.0

FAQ

Does Selenium’s print command download the PDF that the server stores?

No. It creates a new PDF from the currently rendered page. Use the download workflow when preserving the server’s original bytes matters.

Can I save a PDF without opening a browser window?

Yes. Run the print workflow with headless Chromium, or run the configured download workflow in a headless browser. The browser still performs the authenticated navigation and rendering.

Why should I check the %PDF- signature?

A successful navigation or nonempty file can still contain an HTML login page or error response. The signature check catches that mismatch before downstream PDF processing.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Frequently Asked Questions

Does Selenium’s print command download the PDF that the server stores?

No. It creates a new PDF from the currently rendered page. Use the download workflow when preserving the server’s original bytes matters.

Can I save a PDF without opening a browser window?

Yes. Run the print workflow with headless Chromium, or run the configured download workflow in a headless browser. The browser still performs the authenticated navigation and rendering.

Why should I check the %PDF- signature?

A successful navigation or nonempty file can still contain an HTML login page or error response. The signature check catches that mismatch before downstream PDF processing.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.