ScreenshotNeo

BlogHow-to

How to Capture Selenium Screenshots of Indian Flight Booking Websites

Capture a specific flight search state with Selenium, wait for dynamic results, choose the right screenshot scope, and protect booking details.

By the ScreenshotNeo team4 October 202610 min read

Selenium can save the current browser window as a PNG with driver.save_screenshot("flight-results.png"). For a flight search page, first establish the exact search state, wait until its results or fare panel appears, set a repeatable window size, and then capture either the visible window or a specific element. Selenium’s ordinary screenshot methods capture the current window or browsing context; do not describe that result as a full-page screenshot unless you use and verify a separate full-page method. Selenium documents window sizing and current-context screenshots, and its Python API documents the screenshot methods and their return values.

This guide uses Python Selenium for the browser workflow. It also includes cURL, Python requests, and Node.js examples for taking a screenshot through ScreenshotNeo when browser automation is unnecessary.

1. Choose the capture scope and prepare the browser

Decide what the screenshot needs to prove before writing the capture step:

  • Current window: use this for the visible page state, including the search form and the results currently on screen.
  • One element: use an element screenshot for a fare card, result row, price panel, or control. The element must be present and visible, and a large element may extend beyond the viewport depending on browser behavior.
  • Full page: the ordinary save_screenshot and get_screenshot_as_file methods capture the current window. If you need the entire document, use a separately verified browser-specific or Selenium-supported full-page method and confirm its behavior in your target browser and version.

For comparable captures, record the browser and driver environment and explicitly set the window dimensions. Selenium notes that screen resolution can change how an application renders. Set the dimensions before loading the search state, and keep them fixed when comparing screenshots.

Install Selenium

python -m pip install selenium

Use a supported browser installed in your environment. Selenium Manager can help Selenium obtain a compatible driver when needed; in managed or offline environments, provision the browser and driver according to your organization’s setup. Keep browser and driver versions consistent across runs.

2. Capture a flight search result with Python Selenium

The script below navigates to a URL supplied by you, sets a fixed window size, waits for a CSS selector that identifies the result or fare panel you care about, and saves either the current window or that element. Because flight sites use different markup and may require a search form, replace the example selector with one from the page you are authorized to automate. The script does not submit a booking or attempt to bypass a site’s access controls.

#!/usr/bin/env python3
"""Capture a visible flight-search state with Selenium."""

import argparse
from pathlib import Path

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


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("url", help="The flight search page or prepared search URL")
    parser.add_argument("--selector", default="main",
                        help="CSS selector for the result panel to wait for")
    parser.add_argument("--output", default="flight-results.png")
    parser.add_argument("--width", type=int, default=1440)
    parser.add_argument("--height", type=int, default=1000)
    parser.add_argument("--timeout", type=int, default=30)
    parser.add_argument("--element", action="store_true",
                        help="Save the matched element instead of the whole window")
    parser.add_argument("--headed", action="store_true",
                        help="Show the browser window (headless is the default)")
    args = parser.parse_args()

    options = webdriver.ChromeOptions()
    if not args.headed:
        options.add_argument("--headless=new")
    options.add_argument("--force-device-scale-factor=1")
    options.add_argument("--window-size={},{}".format(args.width, args.height))

    driver = webdriver.Chrome(options=options)
    try:
        driver.set_window_size(args.width, args.height)
        driver.get(args.url)

        wait = WebDriverWait(driver, args.timeout)
        target = wait.until(
            EC.visibility_of_element_located((By.CSS_SELECTOR, args.selector))
        )

        output = Path(args.output)
        output.parent.mkdir(parents=True, exist_ok=True)
        if args.element:
            saved = target.screenshot(str(output))
        else:
            saved = driver.save_screenshot(str(output))

        if not saved or not output.is_file() or output.stat().st_size == 0:
            raise OSError("Screenshot was not written: {}".format(output))

        print("Saved {} ({} x {} window)".format(
            output, args.width, args.height
        ))
    except TimeoutException as exc:
        raise SystemExit(
            "Timed out waiting for visible CSS selector {!r}. Check the selector, "
            "search state, consent dialog, and page load.".format(args.selector)
        ) from exc
    finally:
        driver.quit()


if __name__ == "__main__":
    main()

Run it with a prepared results URL and a selector verified for the site and state you are capturing:

python capture_flights.py "https://example.com/your-search-results" \
  --selector "[data-testid='search-results']" \
  --output artifacts/flight-results.png

# Capture just the matched result panel
python capture_flights.py "https://example.com/your-search-results" \
  --selector "[data-testid='fare-card']" \
  --element --output artifacts/fare-card.png

The example domain and selectors are placeholders, not verified airline-site behavior. If the site requires interacting with its search form, add those steps using the site’s normal interface and your approved test account. Prefer a stable test fixture or permitted test environment over a live purchase flow.

Wait for the actual state you need

driver.get() waits for the page-load event, but dynamic fare results may be rendered afterward. A condition-based wait for the target panel is more useful than a fixed sleep because it finishes when the required state is visible and fails clearly when it never appears. For a particular price or result count, wait for the corresponding element or text, not merely a generic page container. If the page updates after initial rendering, wait for the final state you intend to document.

When the correct state is already visible, save a screenshot with:

saved = driver.save_screenshot("flight-results.png")
if not saved:
    raise OSError("Could not write the screenshot")

Selenium also offers driver.get_screenshot_as_file(path), which saves the current window as PNG and returns False on an I/O error. An element can be saved with element.screenshot(path). Choose the method whose scope matches the evidence; a screenshot of a fare card alone may omit the route, date, currency, or filters needed to interpret it.

3. Keep captures repeatable and protect booking data

  1. Use a deliberate viewport. Set width and height explicitly, and record those dimensions with the capture. Also record the browser, driver, operating system, and device scale factor for comparison work.
  2. Wait for a meaningful target. Wait for the intended results, price, or fare card to be visible. A page-load event alone does not establish that asynchronous booking content is ready.
  3. Check the output. Confirm the save operation succeeded and the file is non-empty. Open the PNG and inspect clipping, overlays, unexpected loading states, and whether the target text is legible.
  4. Review privacy before sharing. Flight pages can expose passenger names, contact details, booking references, itinerary information, account details, and payment data. Use synthetic or authorized test data where possible. Crop or redact sensitive details before distribution, and do not publish a screenshot that reveals personal booking data.
  5. Preserve context for interface evidence. If documenting a consent choice or another interface state, capture what the page actually displayed. Do not alter the page and present the resulting image as an unmodified state.

Check the current terms and obtain any required permission before automating a booking site or publishing its page content. For example, Air India’s terms say users are responsible for keeping access information and booking data confidential and restrict copying or distributing website intellectual property without prior written permission. Review Air India’s current terms and check the relevant site’s terms for your own use case.

Consent interfaces also deserve accurate records. A 17 July 2026 Ministry of Consumer Affairs release reported a CCPA penalty against SpiceJet concerning preselected loyalty enrollment and promotional-message choices, and stated that consent should be explicit, informed, and freely given. This is a specific enforcement action, not a claim about every booking site. Read the PIB release.

4. Or skip the browser setup

If the task is simply to get an image of a public page, ScreenshotNeo is a screenshot API and MCP server for developers. One GET request can return PNG, JPEG, WebP, or PDF. It supports full-page capture with lazy images loaded, element capture by CSS selector, custom viewport and device presets, waits for selectors or network idle, and custom headers and cookies. These options can help when the page is accessible without operating its interactive booking flow. Check the ScreenshotNeo API documentation for parameters and authentication.

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

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
r.raise_for_status()
with open("shot.webp", "wb") as image_file:
    image_file.write(r.content)
const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://stripe.com'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const image = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', image));

Replace https://stripe.com with a page you are authorized to capture. The returned image is useful for public pages; it does not replace Selenium when you must enter a search, select dates, or establish a particular interactive state.

  • Cookie banners, popups, and chat widgets are removed before the shot; each cleanup step can be turned off.
  • Bot checks, blank pages, and failed loads are never billed. Response headers report the page verdict and billing status.
  • An MCP server lets AI agents, including Claude, Cursor, and other MCP clients, take screenshots and inspect page information.
  • The Free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.

Create a free ScreenshotNeo account and get 1,000 screenshots a month with no card.

5. Troubleshooting

Symptom Likely cause Fix
Timeout waiting for the selector The selector is wrong, results have not loaded, a search has not been submitted, or a consent overlay is blocking the expected state. Inspect the page in the same browser, verify the selector and search state, and wait for the specific visible result element. Increase the timeout only when the page legitimately needs longer.
Screenshot is blank or shows a spinner The capture happened before the dynamic panel finished rendering, or the target state did not load. Wait for the results or price element and, if necessary, for its loading indicator to disappear. Check the screenshot before treating it as evidence.
Screenshot dimensions differ between runs Window sizing, device scale factor, browser, headless mode, or operating system differs. Set and record the viewport and scale factor; keep the browser/driver environment consistent. Selenium’s window APIs control dimensions, but verify the actual output image dimensions too.
Part of the result is cut off The result is outside the visible window or the element extends beyond the viewport. Scroll the target into view before an element capture, enlarge the window when appropriate, or use a verified full-page method if the whole document is required.
Overlay covers the fare or button A cookie dialog, newsletter prompt, chat panel, or other overlay appeared. For Selenium, handle the consent or overlay through the site’s normal interface where authorized, and record the state. If using ScreenshotNeo on a public page, its known consent platforms, newsletter popups, and chat widgets are removed before capture; cleanup steps can be disabled.
save_screenshot returns false or no file appears The destination directory is missing, unwritable, or the path is invalid. Create the directory, use a writable full path, check the Boolean return, then verify that the file exists and has nonzero size.
Browser fails to start or reports a driver error Browser/driver mismatch, missing browser, restricted download access, or unsupported environment. Install a supported browser, allow Selenium Manager to resolve a driver where permitted, or configure a compatible driver explicitly. Keep versions aligned in CI.
Results differ from a human browser session Different viewport, session state, locale, cookies, personalization, or the site’s automation policy can change the page. Use an authorized test account and controlled state. Do not evade bot checks or access restrictions; use an approved test or capture route instead.

6. Performance, reliability, and cost

A local Selenium capture has no per-screenshot API charge, but it uses browser and driver resources and requires you to maintain their environment. For a small number of screenshots, startup and page loading often dominate the capture step. Reuse a driver for a controlled batch when appropriate, but isolate sessions when state or privacy requires it, and always quit the driver in a finally block.

Reliability comes from controlling inputs and checking outputs: use a stable test page or authorized account, fixed viewport, explicit waits, and file validation. Live fares, availability, localization, personalization, and network timing can change between runs. A screenshot records one observed state; it does not prove that a fare remains available or that a page will render identically later.

ScreenshotNeo pricing is Free for 1,000 shots/month with no card; Starter is $5 for 3,000; Growth $15 for 15,000; Pro $39 for 60,000; Scale $99 for 250,000; and Business $249 for 1,000,000. Yearly billing gives two months free, and every feature is on every plan. Only clean shots are billed: bot checks/CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing. Use Selenium when the page must be driven into a chosen state; use the API when a direct URL capture fits the task.

7. FAQ

Does save_screenshot capture the whole page?

It captures the current window. Use a separately verified full-page method when you need the entire document.

Can I capture one fare card instead of the window?

Yes. Locate the card, wait until it is visible, then call element.screenshot("fare-card.png"). Include enough surrounding context for the image to remain understandable.

Why does the screenshot show stale fares?

The page may have updated after the element first appeared. Wait for the target value or result state to update before capturing, and avoid assuming that a generic results container means its content is current.

Can I publish a screenshot from an airline booking site?

Check the site’s terms and obtain any required permission. Remove personal booking details and consider whether the captured content includes protected material.

Should I use Selenium or a screenshot API?

Use Selenium when you need to interact with the page to establish a search state. A screenshot API is suited to capturing a URL directly when no interactive setup is needed.