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

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

The correct Selenium method depends on what you are looking at. If Selenium rendered an HTML report and you need to create a PDF, call the browser’s print endpoint with print_page, decode the returned Base64 data, and write the bytes to a file. If a URL already serves a PDF, configure the browser to download application/pdf, navigate or click the link, and wait for the completed file. Do not try to automate Chrome’s or Firefox’s built-in PDF viewer with DOM selectors.

Choose the right workflow first

What the tab contains Use What you save Main caveat
HTML report, dashboard or document rendered by the page Selenium print command PDF generated by the browser Layout follows print CSS and browser rendering
An existing PDF returned by a server URL Configured browser download The server’s PDF bytes You must handle download preferences and temporary files

These paths produce different documents. Printing an HTML page is not the same as downloading a PDF that the server has already generated. Decide from the network response or the URL: a response with Content-Type: application/pdf is a download case; an HTML response that displays a report is a print case.

Print a rendered page to PDF (Python)

Selenium’s Python binding exposes driver.print_page(). It returns Base64-encoded PDF data, which you decode before writing. Chromium’s Selenium print example requires headless mode, so the example below enables the current headless implementation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  1. Install Selenium and a compatible Chrome/Chromium driver.
  2. Create the destination directory before starting the browser.
  3. Navigate to the report and wait for its data to finish rendering.
  4. Call print_page, decode the result and write the bytes.
  5. Quit the driver in a finally block.
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

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("https://example.test/report")

    # Add an explicit wait here if the report loads data asynchronously.
    print_options = PrintOptions()
    # Optional: print_options.page_ranges = ["1-3"]
    pdf_b64 = driver.print_page(print_options)
    if not pdf_b64:
        raise RuntimeError("Selenium returned empty PDF data")

    out.write_bytes(base64.b64decode(pdf_b64))
    if out.stat().st_size == 0:
        raise RuntimeError("The PDF file is empty")
finally:
    driver.quit()

The resulting file is a browser-generated PDF. Use PrintOptions for print settings supported by your Selenium binding, including page ranges where available. CSS such as @media print, page breaks and the browser’s print layout affect the output, so a screen-perfect page can legitimately produce a different PDF.

#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

Wait for the report, not merely the URL

driver.get() only guarantees that navigation completed according to the page-load strategy. A single-page application may still be fetching rows or charts. Wait for a distinctive report element, a loading indicator to disappear, or a known application condition before printing. Otherwise the PDF can be valid but incomplete.

Download a PDF that the server already provides

When the tab opens an existing PDF, the viewer is not a normal web page. Selectors aimed at the viewer’s toolbar or document canvas are fragile and browser-specific. Set download behavior before navigation, then wait for the final file.

Firefox: destination, MIME type and viewer bypass

Firefox preferences can specify a download directory and MIME types that should be saved without a prompt. The MIME type must match the server’s response; inspect response headers if the download still opens in the viewer.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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)

opts = Options()
opts.set_preference("browser.download.folderList", 2)
opts.set_preference("browser.download.dir", str(folder))
opts.set_preference("browser.helperApps.neverAsk.saveToDisk", "application/pdf")
# Practical viewer-bypass preference; verify it with the Firefox version in CI.
opts.set_preference("pdfjs.disabled", True)

driver = webdriver.Firefox(options=opts)
try:
    driver.get("https://example.test/files/report.pdf")
finally:
    driver.quit()

pdfjs.disabled is version-sensitive. Keep it as a project setting only after verifying it with the Firefox build used in local and CI runs.

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)

Chrome or Chromium: download instead of opening

Chrome’s user setting is Settings → Privacy and security → Site Settings → Additional content settings → PDF documents → Download PDFs. Automated sessions should also set an explicit download directory through the Chrome options or preferences supported by the Selenium binding and environment. Configure it before calling get() or clicking the PDF link.

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

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

options = Options()
options.add_experimental_option("prefs", {
    "download.default_directory": str(folder),
    "download.prompt_for_download": False,
    "download.directory_upgrade": True,
    "plugins.always_open_pdf_externally": True,
})
driver = webdriver.Chrome(options=options)
try:
    driver.get("https://example.test/files/report.pdf")
finally:
    driver.quit()

Preference names and driver behavior can vary by browser version and execution environment. If your binding exposes a browser-specific download command, use that in addition to the profile preferences.

Wait for the completed file safely

Downloads are asynchronous. Chromium commonly writes a .crdownload file while Firefox commonly uses .part. A robust test cleans the directory first, waits for the expected final name (or a newly created PDF), requires a nonzero size, and confirms that no temporary file remains.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import time
from pathlib import Path

def wait_for_pdf(folder: Path, timeout: float = 60) -> Path:
    deadline = time.monotonic() + timeout
    while time.monotonic() < deadline:
        temporary = list(folder.glob("*.crdownload")) + list(folder.glob("*.part"))
        pdfs = [p for p in folder.glob("*.pdf") if p.is_file() and p.stat().st_size > 0]
        if pdfs and not temporary:
            candidate = max(pdfs, key=lambda p: p.stat().st_mtime)
            with candidate.open("rb") as fh:
                if fh.read(5) != b"%PDF-":
                    raise RuntimeError(f"Not a PDF: {candidate}")
            return candidate
        time.sleep(0.25)
    raise TimeoutError(f"No completed PDF appeared in {folder}")

Use a deterministic filename when the application supplies one, or rename the newly detected file after validation. Never accept an old file left by a previous run: remove or isolate the directory at test start.

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

Authentication and session handling

A PDF link may require the same login as the surrounding application. Navigating with Selenium preserves the browser’s cookies, local state and interactive authentication. If you replace the browser download with an HTTP client, transfer every requirement deliberately: cookies, authorization headers, redirects, user-agent expectations and any anti-bot challenge. Otherwise the client may save an HTML login page with a .pdf name.

For a known URL, direct retrieval can be simpler:

import requests

response = requests.get(
    "https://example.test/files/report.pdf",
    cookies={"session": "..."},
    timeout=60,
)
response.raise_for_status()
if response.headers.get("Content-Type", "").split(";", 1)[0].lower() != "application/pdf":
    raise RuntimeError("The response is not an application/pdf")
with open("artifacts/report.pdf", "wb") as fh:
    fh.write(response.content)

Use this only when the request is known to be equivalent to the authenticated browser request. Selenium is safer when redirects, short-lived tokens or browser-only checks are involved.

Print versus download: fidelity, control and CI stability

Criterion Print API Browser download
Input Rendered HTML Existing PDF response
Fidelity Browser layout, fonts and @media print Server-produced bytes
Browser control PrintOptions and print command Download directory, MIME preferences and viewer settings
Authentication Uses current Selenium session Uses current session when navigated or clicked
CI concerns Headless Chromium requirement in the documented example; wait for page data Temporary files, filename collisions and browser-specific preferences

Choose print when the browser is the document generator and download when the server is. Converting a server PDF to a printed PDF can change text selection, metadata, pagination and visual fidelity.

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

Verification checklist

  • Use a clean, dedicated output directory for each run.
  • Wait for the expected file and for .crdownload or .part files to disappear.
  • Require a nonzero file size.
  • Check that the first five bytes are %PDF-, or parse the document with a PDF library.
  • For print output, verify the Base64 return value before decoding.
  • Record the final path in test logs so a CI failure is diagnosable.

Troubleshooting common failures

The file is HTML, not PDF

The request probably reached a login page, error page or bot check. Inspect the response headers and the first bytes, then authenticate in the Selenium session or transfer the required cookies and headers for a direct request.

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.

Chrome still opens the viewer

Set the download preferences before navigation, include external-PDF handling where supported, and confirm the profile is not being replaced by a managed CI policy. Do not rely on clicking the viewer’s Save button.

Firefox prompts or opens PDF.js

Check that browser.helperApps.neverAsk.saveToDisk contains the exact server MIME type, including a possible vendor-specific PDF type. Verify pdfjs.disabled against the Firefox version in use.

The wait times out

Log the directory contents during polling. A wrong directory, a download blocked by policy, a different filename, a still-present temporary file or a failed HTTP response are the usual causes. Increase the timeout only after identifying which condition is slow.

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

print_page returns empty or fails

Ensure the page has finished rendering, use a supported Selenium/browser combination, and run Chromium headless as in the documented example. Check that the returned value is present before Base64 decoding.

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

The printed PDF misses charts or rows

Wait on a report-specific readiness condition rather than a fixed short sleep. For pages that lazy-load content, scroll or trigger the application’s own completion signal before invoking print.

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

Or skip the browser setup

For a URL you simply need captured as a PDF, ScreenshotNeo provides a one-call API. It can accept the consent banner like a visitor and remove more than 60 known consent platforms, newsletter popups and chat widgets before capture; each cleanup step can be disabled. Bot checks, blank pages, failed loads and timeouts are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers. An MCP server lets Claude, Cursor and other MCP clients use take_screenshot, get_page_info and capture_pdf.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.pdf

See the ScreenshotNeo documentation for PDF parameters such as paper size, margins, landscape mode and page ranges. The free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Sign up at ScreenshotNeo.

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

Python and Node.js API alternatives

Python

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.pdf", "wb").write(r.content)

Node.js

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
const data = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.pdf', data));

Use the API when you do not need a live browser session, viewer interaction or application-specific login flow. Selenium remains the appropriate choice when the PDF depends on an authenticated, stateful browser or when you must reproduce print CSS exactly.

Frequently Asked Questions

Can Selenium save a PDF opened in a new tab?

Yes. Configure downloads before the action that opens the tab, switch to the new window if needed, and monitor the configured download directory rather than the PDF viewer DOM.

How can I control the output filename?

The server may choose the download name. Detect and validate the newly completed file, then rename it to a deterministic name in your own output directory.

Does Selenium’s print command preserve the original server PDF?

No. It creates a new PDF from the rendered page. Preserve the original bytes by downloading the server response instead.

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

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.