Some checks failed
Build & Deploy to Staging / Build & Deploy to Staging (push) Has been cancelled
- Add clip object parameter to crop rectangular areas from screenshots
- Support POST body: clip {x, y, width, height} number fields
- Support GET query: clipX, clipY, clipW, clipH params
- Validation: all fields required, x/y >=0, width/height >0, max 3840x2160
- Mutually exclusive with fullPage and selector
- Update OpenAPI docs with clip examples
- Update Node.js and Python SDK READMEs with clip usage
- Add comprehensive test coverage (11 new tests)
- Tests: missing fields, negative coords, zero dimensions, max limits, mutual exclusivity
238 lines
5.4 KiB
Markdown
238 lines
5.4 KiB
Markdown
# SnapAPI Python SDK
|
||
|
||
Official Python client for [SnapAPI](https://snapapi.eu) — the EU-hosted screenshot API.
|
||
|
||
**Zero dependencies.** Uses only Python standard library (`urllib`).
|
||
|
||
## Installation
|
||
|
||
```bash
|
||
pip install snapapi
|
||
```
|
||
|
||
## Quick Start
|
||
|
||
```python
|
||
from snapapi import SnapAPI
|
||
|
||
snap = SnapAPI("your-api-key")
|
||
|
||
# Capture a screenshot
|
||
screenshot = snap.capture("https://example.com")
|
||
|
||
with open("screenshot.png", "wb") as f:
|
||
f.write(screenshot)
|
||
```
|
||
|
||
## Usage
|
||
|
||
### Basic Screenshot
|
||
|
||
```python
|
||
png = snap.capture("https://example.com")
|
||
```
|
||
|
||
### With Options
|
||
|
||
```python
|
||
jpg = snap.capture(
|
||
"https://example.com",
|
||
format="jpeg",
|
||
width=1920,
|
||
height=1080,
|
||
quality=90,
|
||
)
|
||
```
|
||
|
||
### Full-Page Capture
|
||
|
||
```python
|
||
full = snap.capture(
|
||
"https://example.com/blog",
|
||
full_page=True,
|
||
device_scale=2, # Retina
|
||
)
|
||
```
|
||
|
||
### Mobile Viewport
|
||
|
||
```python
|
||
mobile = snap.capture(
|
||
"https://example.com",
|
||
width=375,
|
||
height=812,
|
||
device_scale=2,
|
||
)
|
||
```
|
||
|
||
### Wait for Dynamic Content
|
||
|
||
```python
|
||
screenshot = snap.capture(
|
||
"https://example.com/dashboard",
|
||
wait_for_selector="#chart-loaded",
|
||
wait_until="networkidle2",
|
||
)
|
||
```
|
||
|
||
### Dark Mode Capture
|
||
|
||
```python
|
||
# Capture in dark mode (prefers-color-scheme: dark)
|
||
dark_screenshot = snap.capture(
|
||
"https://example.com",
|
||
dark_mode=True,
|
||
format="png",
|
||
)
|
||
```
|
||
|
||
### Custom User Agent
|
||
|
||
```python
|
||
# Set a custom User-Agent string for the request
|
||
screenshot = snap.capture(
|
||
"https://example.com",
|
||
user_agent="Mozilla/5.0 (compatible; SnapAPI/1.0)",
|
||
format="png",
|
||
)
|
||
```
|
||
|
||
### Hide Elements Before Capture
|
||
|
||
```python
|
||
# Hide cookie banners, popups, ads
|
||
clean_screenshot = snap.capture(
|
||
"https://example.com",
|
||
hide_selectors=[
|
||
".cookie-banner",
|
||
".popup-overlay",
|
||
"#advertisement",
|
||
".tracking-notice"
|
||
],
|
||
)
|
||
|
||
# Hide single element
|
||
single_hide = snap.capture(
|
||
"https://example.com",
|
||
hide_selectors=".newsletter-popup",
|
||
)
|
||
```
|
||
|
||
### Custom CSS Injection
|
||
|
||
```python
|
||
# Inject custom CSS before capture
|
||
styled = snap.capture(
|
||
"https://example.com",
|
||
css='body { background: #1a1a2e !important; color: #eee !important }',
|
||
)
|
||
|
||
# Combine with other options
|
||
combined = snap.capture(
|
||
"https://example.com",
|
||
css=".hero { padding: 80px 0 } h1 { font-size: 48px }",
|
||
dark_mode=True,
|
||
hide_selectors=[".cookie-banner"],
|
||
)
|
||
```
|
||
|
||
### JavaScript Injection
|
||
|
||
```python
|
||
# Execute custom JavaScript before capture
|
||
interactive_screenshot = snap.capture(
|
||
"https://example.com",
|
||
js="""
|
||
// Dismiss modal popup
|
||
document.querySelector('.modal-overlay')?.remove();
|
||
|
||
// Scroll to specific content
|
||
window.scrollTo(0, 500);
|
||
|
||
// Click button to reveal content
|
||
document.querySelector('#show-more-btn')?.click();
|
||
|
||
// Wait for animation to complete
|
||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||
""",
|
||
)
|
||
|
||
# Combine with other options for complex scenarios
|
||
complex_capture = snap.capture(
|
||
"https://example.com/app",
|
||
js='document.querySelector(".sidebar").style.display = "none";',
|
||
css="body { zoom: 0.8 }",
|
||
wait_for_selector="#content-loaded",
|
||
hide_selectors=[".ad-banner", ".cookie-notice"],
|
||
)
|
||
```
|
||
|
||
### Crop Specific Areas (Clip)
|
||
|
||
```python
|
||
# Crop a specific rectangular area from the screenshot
|
||
cropped_screenshot = snap.capture(
|
||
"https://example.com",
|
||
clip={
|
||
"x": 100, # X coordinate (pixels from left)
|
||
"y": 50, # Y coordinate (pixels from top)
|
||
"width": 800, # Width of the crop area
|
||
"height": 600, # Height of the crop area
|
||
},
|
||
)
|
||
|
||
# Useful for capturing specific UI elements or sections
|
||
header_screenshot = snap.capture(
|
||
"https://example.com",
|
||
clip={"x": 0, "y": 0, "width": 1280, "height": 120}, # Top banner only
|
||
format="png",
|
||
)
|
||
```
|
||
|
||
### Error Handling
|
||
|
||
```python
|
||
from snapapi import SnapAPI, SnapAPIError
|
||
|
||
snap = SnapAPI("your-api-key")
|
||
|
||
try:
|
||
screenshot = snap.capture("https://example.com")
|
||
except SnapAPIError as e:
|
||
print(f"API error {e.status}: {e.detail}")
|
||
```
|
||
|
||
## API Reference
|
||
|
||
### `SnapAPI(api_key, base_url="https://snapapi.eu", timeout=30)`
|
||
|
||
### `snap.capture(url, **options) -> bytes`
|
||
|
||
| Option | Type | Default | Description |
|
||
|--------|------|---------|-------------|
|
||
| `url` | `str` | — | URL to capture (required) |
|
||
| `format` | `str` | `"png"` | Output: `png`, `jpeg`, `webp` |
|
||
| `width` | `int` | `1280` | Viewport width (320–3840) |
|
||
| `height` | `int` | `800` | Viewport height (200–2160) |
|
||
| `full_page` | `bool` | `False` | Capture full page |
|
||
| `quality` | `int` | `80` | JPEG/WebP quality (1–100) |
|
||
| `wait_for_selector` | `str` | — | CSS selector to wait for |
|
||
| `device_scale` | `float` | `1` | Device pixel ratio (1–3) |
|
||
| `delay` | `int` | `0` | Extra delay in ms (0–5000) |
|
||
| `wait_until` | `str` | `"domcontentloaded"` | Load event |
|
||
| `dark_mode` | `bool` | `False` | Emulate prefers-color-scheme: dark |
|
||
| `hide_selectors` | `list` | — | CSS selectors to hide before capture |
|
||
| `css` | `str` | — | Custom CSS to inject before capture (max 5000 chars) |
|
||
| `clip` | `dict` | — | Crop rectangle: `{"x": int, "y": int, "width": int, "height": int}` (mutually exclusive with full_page/selector) |
|
||
|
||
### `snap.health() -> dict`
|
||
|
||
Returns API health status.
|
||
|
||
## EU-Hosted & GDPR Compliant
|
||
|
||
SnapAPI runs entirely on EU infrastructure (Germany). Your data never leaves the EU.
|
||
|
||
## License
|
||
|
||
MIT — [Cloonar Technologies GmbH](https://snapapi.eu)
|