How to Take Screenshots of Web Pages with zendriver: A Complete Guide
Use Tab.screenshot_b64() or Tab.save_screenshot() for full-page captures, and Element.screenshot_b64() or Element.save_screenshot() for specific DOM elements in the zendriver library.
The zendriver library provides asynchronous Python APIs for controlling Chrome through the Chrome DevTools Protocol (CDP), including robust screenshot capabilities for both entire web pages and individual elements. Whether you need to capture full-page renders for visual regression testing or isolate specific UI components, zendriver abstracts the underlying CDP complexity into simple methods on Tab and Element objects. This guide covers the implementation details, configuration options, and source code structure you need to take screenshots of web pages effectively.
Full-Page and Viewport Screenshots
The Tab class in zendriver/core/tab.py exposes two primary methods for capturing page-level screenshots. According to the source code at lines 1313–1350, both methods automatically wait for the page to settle before invoking the CDP command to ensure stable captures.
Capturing Base-64 Data
Use screenshot_b64() when you need the image data as a Base-64 encoded string for further processing or API uploads:
async def get_page_image(tab):
# Returns a Base-64 string of the full page
b64_data = await tab.screenshot_b64(format="png", full_page=True)
return b64_data
The format parameter accepts "jpeg" (default) or "png", while full_page determines whether to capture the entire scrollable document (True) or only the current viewport (False).
Saving to Disk
Use save_screenshot() to write the image directly to the filesystem. This method handles Base-64 decoding internally using base64.b64decode and automatically generates a filename if omitted:
async def save_page_image(tab):
saved_path = await tab.save_screenshot(
"homepage.png",
format="png",
full_page=True
)
print(f"Screenshot saved to: {saved_path}")
If the page isn't ready, these methods raise a ProtocolException as implemented in the error handling logic at lines 1329–1345 of zendriver/core/tab.py.
Element-Level Screenshots
For capturing specific DOM elements, the Element class in zendriver/core/element.py (lines 867–904) provides analogous methods that clip the screenshot to the element's bounding box.
Isolating Specific Components
After locating an element using query_selector(), you can capture it independently of the rest of the page:
async def capture_header(tab):
header = await tab.query_selector("header#main")
if header:
# Save with 2x resolution for high-DPI displays
await header.save_screenshot("header.jpg", format="jpeg", scale=2)
The scale parameter multiplies the captured dimensions, allowing you to generate higher resolution images (e.g., scale=2 captures at double the element's size). Under the hood, the method calculates the viewport rectangle using pos.to_viewport(scale) and passes it as the clip parameter to the CDP command.
Error Handling
If the target element is hidden or lacks geometry (zero width/height), Element.screenshot_b64() raises a RuntimeError according to the validation logic at lines 867–888 of zendriver/core/element.py.
CDP Implementation Details
Both screenshot APIs delegate to the Chrome DevTools Protocol command Page.captureScreenshot, defined in zendriver/cdp/page.py at lines 2259–2274. The Tab implementation calls cdp.page.capture_screenshot(format_, capture_beyond_viewport=full_page) directly, while the Element implementation constructs a clip rectangle from the element's position data before making the same CDP call.
The actual image encoding and file I/O occur in the high-level methods:
Tab.save_screenshot()decodes the CDP response and writes binary PNG/JPEG dataElement.save_screenshot()performs the same decoding but applies the calculated clip region to isolate the element
Complete Working Example
This standalone script demonstrates the full workflow from browser initialization to capturing both full-page and element-specific screenshots:
import asyncio
from zendriver import Browser, Tab
async def main():
async with Browser(headless=True) as browser:
tab: Tab = await browser.new_tab("https://example.com")
# Wait for page load to ensure elements are rendered
await tab.wait_for_load()
# Capture full-page screenshot
await tab.save_screenshot("full_page.png", full_page=True)
# Capture specific element
logo = await tab.query_selector("img.logo")
if logo:
await logo.save_screenshot("logo_element.png", scale=2)
if __name__ == "__main__":
asyncio.run(main())
The script follows best practices by awaiting tab.wait_for_load() before screenshotting to ensure the DOM is fully rendered and stable.
Summary
- Full-page captures: Use
Tab.screenshot_b64()for Base-64 data orTab.save_screenshot()for file output; both supportfull_page=Trueto capture beyond the viewport. - Element isolation: Use
Element.screenshot_b64()orElement.save_screenshot()with optionalscaleparameter for high-resolution element captures. - Core files: Implementation resides in
zendriver/core/tab.py(page-level) andzendriver/core/element.py(element-level), with the underlying CDP command defined inzendriver/cdp/page.py. - Error handling: Expect
ProtocolExceptionif the page isn't ready, andRuntimeErrorif attempting to screenshot hidden elements.
Frequently Asked Questions
What image formats does zendriver support for screenshots?
zendriver supports JPEG (default) and PNG formats via the format parameter in both Tab and Element screenshot methods. JPEG offers smaller file sizes for photographs, while PNG preserves transparency and sharp edges for UI elements.
How do I capture a full-page screenshot instead of just the viewport?
Pass full_page=True to Tab.screenshot_b64() or Tab.save_screenshot(). This sets capture_beyond_viewport=True in the underlying CDP Page.captureScreenshot command, instructing Chrome to capture the entire scrollable document rather than only the visible viewport.
Can I take screenshots of hidden elements?
No. If an element has no visible geometry (zero width or height) or is hidden via CSS, Element.screenshot_b64() raises a RuntimeError according to the validation in zendriver/core/element.py lines 867–888. You must ensure the element is visible and rendered before attempting capture.
Where are the screenshot methods implemented in the source code?
The Tab screenshot methods are implemented in zendriver/core/tab.py at lines 1313–1350, while Element screenshot methods live in zendriver/core/element.py at lines 867–904. Both delegate to the CDP command defined in zendriver/cdp/page.py at lines 2259–2274.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →