Python guide · Published October 16, 2026 · 9 min read
Take a Website Screenshot in Python: 5 Ways Compared (Selenium vs Playwright vs API)
Quick answer
To take a screenshot of a website in Python, install Playwright (pip install playwright and playwright install chromium), open the URL and call page.screenshot(path="page.png", full_page=True). Use Selenium if you already have it, the headless Chrome CLI for a dependency-free one-off, and a screenshot API when you need thousands of captures without running browsers.
"Screenshot in Python" means two different things on Stack Overflow: capturing your desktop, and capturing a web page from a URL. This guide is about the second one. We ran all five approaches against the same Wikipedia article on a MacBook with Chrome installed, using the code below unchanged, and wrote down what each one returned.
The comparison
| Method | Full page | Element | Waits for content | Setup | Our result |
|---|---|---|---|---|---|
| Playwright | Yes, one flag | Yes | Auto-waits on locators | pip + browser download | 1280×4611, full article |
| Selenium | Firefox only, or CDP in Chrome | Yes | Explicit waits | pip; driver auto-managed | 1280×657, viewport |
| Headless Chrome CLI | No, fixed window | No | No | Chrome only | 1280×800, viewport |
| html2image | No, fixed size | No | No | pip + Chrome | 1280×800, viewport |
| Screenshot API | Yes, one parameter | Yes (selector) | Yes (wait parameters) | pip install requests | Depends on parameters |
Timings on a single cold run ranged from about 1.4 s (Selenium, Chrome CLI) to 3.5 s (Playwright with a full-page capture). That is one run on one laptop, so treat it as a rough order, not a benchmark.
1Playwright for Python
Of the four local methods, this is the only one that captured the whole article without extra code. Options use snake_case in Python (full_page, omit_background), and there is an async API (playwright.async_api) if your app is already async. Every option is explained in our Playwright screenshot guide.
2Selenium
Selenium Manager downloads the matching chromedriver automatically, so pip install selenium is enough. The surprise in our run: the PNG was 1280×657, not 1280×800. --window-size sets the outer window, and the browser's own UI takes part of that height. If the exact viewport matters, set a taller window or capture through the DevTools Protocol.
For full pages you need Firefox's save_full_page_screenshot() or the CDP command Page.captureScreenshot in Chrome. Both are in our Selenium screenshot guide with working code.
3Headless Chrome from subprocess
Chrome's own --screenshot flag writes a PNG of the window size you pass, and the result was exactly 1280×800. Passing an absolute path, as above, keeps the output location independent of where the script is started. There is no way to wait for a selector, so pages that render late come out half empty.
4html2image
html2image is a thin wrapper around the same headless Chrome flag as method 3, with a friendlier API and the ability to render HTML strings. It finds an installed Chrome or Edge, or you pass browser_executable. If rendering your own templates is the main job, our HTML to image guide compares the options. The trade-offs are the same as the CLI: fixed size and no waiting.
5A screenshot API
The browser runs on the API side, so your Python environment only needs requests. That matters on AWS Lambda, in small containers and in notebooks. For hundreds of URLs at once, the batch endpoint captures up to 10 per request. Parameters such as wait_for_selector, selector, dark_mode and device_scale_factor replace the code you would otherwise write around Playwright.
Tools that look right but capture the wrong thing
| Library | What it actually captures |
|---|---|
pyautogui.screenshot() | Your monitor, pixel by pixel. The page must be open and visible. |
PIL.ImageGrab.grab() | Your monitor or a region of it. Same limitation. |
mss | Fast multi-monitor screen capture. Great for desktop apps, not for URLs. |
pyppeteer | Web pages, but its README says the repo is unmaintained and suggests playwright-python. |
If you search "screenshot in python" and land on one of these, that is why your code cannot see anything below the fold or anything on a headless server.
Which one to pick
| Your situation | Use |
|---|---|
| New script, full pages, JavaScript-heavy sites | Playwright |
| Screenshots inside existing Selenium tests | Selenium |
| One static page, no packages allowed | Headless Chrome CLI |
| Rendering your own HTML templates to PNG | html2image (or an API with an html parameter) |
| Hundreds of URLs, Lambda, notebooks, no browser | Screenshot API |
Takeaways
- Playwright and an API give you a full-page capture with a single option; Selenium does it in one call only on Firefox.
- Selenium's window size is not the viewport size; check your output dimensions.
- The CLI and html2image are fine for static pages and generated HTML, not for apps that render late.
- Desktop capture libraries cannot screenshot a URL.
Sources
FAQ
What is the best Python library to screenshot a website?
For most scripts, Playwright for Python. It installs its own browser, supports full-page and element screenshots in one call, and waits for elements automatically. Use Selenium if your project already runs Selenium tests.
How do I take a full-page screenshot of a website in Python?
With Playwright: page.screenshot(path='page.png', full_page=True). Selenium needs Firefox (save_full_page_screenshot) or a Chrome DevTools command, and the headless Chrome CLI and html2image only capture a fixed window size.
Can PIL ImageGrab or pyautogui screenshot a website?
They capture your physical screen, not a URL. They work only if the page is open and visible on your monitor, and they cannot capture content below the fold.
Is pyppeteer still a good choice?
The pyppeteer README says the repository is unmaintained and suggests playwright-python as the alternative, so new code should use Playwright instead.
Why is my Selenium screenshot shorter than the window size I set?
With --window-size, the size includes the browser window itself, so the page viewport is smaller. In our test, --window-size=1280,800 in headless Chrome produced a 1280x657 screenshot.
Screenshots from Python without a browser
One requests.get() returns a full-page PNG, WebP or PDF, with cookie banners blocked and JavaScript rendered. The free tier gives you 300 screenshots, no credit card required.