October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run ScanOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk7 min

How to Bulk Screenshot a List of URLs with Playwright in Python

A practical Playwright Python batch script for saving full-page screenshots of multiple URLs, with concurrency controls, reliable cleanup, and fixes for common failures.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use Playwright’s asynchronous Python API to open each URL in a fresh page, save a screenshot, and close the page—even when an individual navigation fails. The example below bounds concurrent pages, creates a separate PNG for each URL, and closes the browser context and browser when the batch is done. Use full_page=True to capture the whole scrollable document instead of only the visible viewport.

Install Playwright and its browser

Install the Python package and Chromium before running the script:

As an Amazon Associate I earn from qualifying purchases.

  1. python -m pip install playwright
  2. python -m playwright install chromium

The example uses Python’s asyncio API. Playwright provides both synchronous and asynchronous Python APIs; async is a natural fit when the rest of your application already uses asyncio. See the Playwright Python getting-started documentation.

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

Run a batch with bounded concurrency

Save this as bulk_screenshots.py. It writes one full-page PNG per URL in the screenshots directory. The four-page limit is an example, not a recommended maximum: adjust it for your machine, the pages you capture, and the load appropriate for target sites.

import asyncio
from pathlib import Path
from playwright.async_api import async_playwright

URLS = [
    "https://example.com/",
    "https://playwright.dev/python/",
]
OUT = Path("screenshots")
MAX_CONCURRENT_PAGES = 4  # Example only; tune for your workload.

async def main():
    OUT.mkdir(parents=True, exist_ok=True)
    semaphore = asyncio.Semaphore(MAX_CONCURRENT_PAGES)

    async with async_playwright() as p:
        browser = await p.chromium.launch()
        context = await browser.new_context(
            viewport={"width": 1440, "height": 1000}
        )

        async def capture(index, url):
            async with semaphore:
                page = await context.new_page()
                try:
                    response = await page.goto(
                        url, wait_until="load", timeout=30_000
                    )
                    # A response may be absent for some non-HTTP navigations.
                    status = response.status if response else None
                    output_path = OUT / f"{index:04d}.png"
                    await page.screenshot(
                        path=str(output_path), full_page=True
                    )
                    return {
                        "url": url,
                        "status": status,
                        "file": str(output_path),
                    }
                except Exception as exc:
                    return {"url": url, "error": str(exc)}
                finally:
                    await page.close()

        try:
            results = await asyncio.gather(
                *(capture(index, url)
                  for index, url in enumerate(URLS, start=1))
            )
        finally:
            await context.close()
            await browser.close()

    for result in results:
        print(result)

asyncio.run(main())

Run it with python bulk_screenshots.py. The output names are based on the URL’s position in the input list, not on raw URL text, so characters such as slashes and query strings cannot accidentally become part of a path. If you run the same list again, matching filenames are overwritten; use a run-specific directory or stable unique identifiers if you need to retain earlier batches.

Choose what the screenshot should include

Viewport or full page

The script sets full_page=True, which captures the complete scrollable page as one image. Set it to False or omit it for a screenshot limited to the viewport configured when the browser context was created. A full-page image can be very tall; choose viewport capture if the consumer expects a screen-sized image. Playwright documents the screenshot options.

Wait for the right page state

wait_until="load" waits for the page load event, but it does not guarantee that client-side rendering, delayed content, or lazy-loaded images are finished. When a site needs additional time or a known element, wait for that condition before taking the screenshot—for example:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
await page.goto(url, wait_until="load", timeout=30_000)
await page.locator("main article").wait_for(state="visible", timeout=10_000)
await page.screenshot(path=str(output_path), full_page=True)

Replace main article with a selector meaningful for the target page. Avoid adding a fixed delay to every capture unless the site requires it; a page-specific readiness check is usually more targeted.

Save to a file or capture bytes

For a straightforward batch, pass path to page.screenshot() as the main script does. If the next step is image processing or uploading rather than local file output, omit path and use the returned bytes:

image_bytes = await page.screenshot(full_page=True)

Playwright’s screenshot API supports both saving to a path and returning image bytes.

Choose how to manage pages and browser state

Reuse a context for consistent settings

The sample creates one browser context and a fresh page for each URL. Pages in the same context share context-level settings, such as viewport emulation. This is useful when every capture should use the same browser configuration. Close each page after capture, then close the context and browser; the try/finally blocks ensure cleanup even if a capture raises an exception. See Playwright’s documentation on multiple pages and browser contexts, as well as its browser lifecycle API.

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.

Use separate contexts when sessions must be isolated

A browser context represents an isolated browser session. If URLs must not share session state, cookies, or other context-level configuration, create a separate context for the relevant captures and close it when finished. This uses more browser resources than sharing one context, so choose isolation to meet a real requirement rather than creating a new context automatically for every URL.

Tune concurrency, failures, and output for your batch

Set concurrency deliberately

The semaphore limits how many captures enter the page-creation and navigation section at once. More parallel work may reduce elapsed time for some workloads, but it also uses more local resources and sends more simultaneous requests to target sites. Start conservatively and adjust based on observed memory use, failures, and acceptable site load. Playwright does not publish a universal best number of concurrent pages or a throughput guarantee for this workflow.

Keep errors tied to individual URLs

Each capture catches its own exception and returns an error record, allowing other URLs to finish. The navigation response status is recorded when available, but an HTTP response such as a 404 is not itself a navigation exception; inspect the returned status if your workflow should treat non-success responses as failures. A None status means no response object was returned, not that the page necessarily succeeded.

Make names stable when needed

The index-based names are unique within this run and easy to sanitize, but reordering the input changes which URL receives each number. If reproducibility matters, assign each URL a stable identifier and sanitize it before using it in a filename. Do not use an untrusted raw URL as a filesystem path.

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

Use a synchronous script for a small one-off batch

If your script is not part of an async application, Playwright’s synchronous API can be simpler to read. The core sequence is the same: start Playwright, launch a browser, create a context and page, navigate, capture, and close resources.

from pathlib import Path
from playwright.sync_api import sync_playwright

urls = ["https://example.com/", "https://playwright.dev/python/"]
out = Path("screenshots")
out.mkdir(parents=True, exist_ok=True)

with sync_playwright() as p:
    browser = p.chromium.launch()
    context = browser.new_context(viewport={"width": 1440, "height": 1000})
    try:
        for index, url in enumerate(urls, start=1):
            page = context.new_page()
            try:
                response = page.goto(url, wait_until="load", timeout=30_000)
                status = response.status if response else None
                path = out / f"{index:04d}.png"
                page.screenshot(path=str(path), full_page=True)
                print({"url": url, "status": status, "file": str(path)})
            except Exception as exc:
                print({"url": url, "error": str(exc)})
            finally:
                page.close()
    finally:
        context.close()
        browser.close()

This version processes URLs sequentially. Use the async pattern when you want bounded overlapping work or need to integrate with an asyncio application; async syntax alone does not establish a particular throughput advantage.

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

Troubleshoot common failures

  • Browser executable missing: install Chromium with python -m playwright install chromium after installing the package.
  • Navigation timeout: the site may be slow, unreachable, or waiting on resources that never finish. Check the URL and network access, then consider a longer per-site timeout or a different readiness condition such as domcontentloaded plus a selector wait. Do not increase every timeout blindly.
  • Screenshot misses content: the page may render important content after the load event. Wait for a relevant visible selector or another application-specific condition before capturing.
  • One URL disrupts a batch: keep exception handling inside the per-URL capture function, as shown, so failures are returned alongside successful results.
  • Images are overwritten: the sample reuses numbered filenames. Use a unique output directory per run or stable identifiers if previous results must be preserved.
  • High memory use or excessive target load: lower MAX_CONCURRENT_PAGES. The right limit depends on the pages, host machine, and target sites.

Or skip the browser setup

ScreenshotNeo offers a hosted screenshot API; its website screenshot API can return an image or PDF from one GET request. For a PNG, JPEG, or WebP response, save the returned bytes to a file. The example follows the API’s documented usage; see the ScreenshotNeo documentation.

import requests

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

ScreenshotNeo removes supported cookie and consent banners, newsletter popups, and chat widgets before capture; those cleanup steps can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing status. Its MCP server provides screenshot tools for AI agents and MCP clients. The Free plan includes 1,000 shots a month with no card; paid plans start at $5 for 3,000 shots. Sign up for 1,000 free screenshots a month—no card required.

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

Frequently Asked Questions

Does the script capture one screenshot per URL?

Yes. Each URL gets a fresh page and a distinct numbered PNG in the output directory.

Can I capture PDF files instead of images with Playwright?

This example uses Playwright’s screenshot API and writes PNG images; PDF output is a separate browser workflow and is not shown here.

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.

Leave a Reply

Your email address will not be published. Required fields are marked *

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.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Outdated Drivers Are Slowing You DownFree scan - exact matches
PC Slower Than It Used to Be?Free scan - under a minute

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.