snapapi-python 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,113 @@
1
+ Metadata-Version: 2.2
2
+ Name: snapapi-python
3
+ Version: 0.1.1
4
+ Summary: Python SDK for the SnapAPI web intelligence API — screenshots, metadata, PDF, page analysis
5
+ Home-page: https://snapapi.tech
6
+ Author: SnapAPI
7
+ Author-email: hello@snapapi.tech
8
+ License: MIT
9
+ Project-URL: Documentation, https://snapapi.tech/docs
10
+ Project-URL: Source, https://github.com/Boehner/snapapi-python
11
+ Project-URL: Bug Tracker, https://github.com/Boehner/snapapi-python/issues
12
+ Keywords: screenshot api web-scraping metadata pdf puppeteer snapapi
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.8
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Topic :: Internet :: WWW/HTTP
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Requires-Python: >=3.8
25
+ Description-Content-Type: text/markdown
26
+ Dynamic: author
27
+ Dynamic: author-email
28
+ Dynamic: classifier
29
+ Dynamic: description
30
+ Dynamic: description-content-type
31
+ Dynamic: home-page
32
+ Dynamic: keywords
33
+ Dynamic: license
34
+ Dynamic: project-url
35
+ Dynamic: requires-python
36
+ Dynamic: summary
37
+
38
+ # snapapi-python
39
+
40
+ Python SDK for the [SnapAPI](https://snapapi.tech) web intelligence API. Zero dependencies — uses only the Python standard library.
41
+
42
+ ```bash
43
+ pip install snapapi-python
44
+ ```
45
+
46
+ ## Quick Start
47
+
48
+ ```python
49
+ from snapapi import SnapAPI
50
+
51
+ client = SnapAPI() # reads SNAPAPI_KEY from environment
52
+
53
+ # Screenshot
54
+ png = client.screenshot("https://github.com", full_page=True)
55
+ open("screenshot.png", "wb").write(png)
56
+
57
+ # Metadata
58
+ meta = client.metadata("https://github.com")
59
+ print(meta["og_title"]) # "GitHub: Let's build from here"
60
+ print(meta["og_image"]) # "https://..."
61
+
62
+ # Full page analysis
63
+ data = client.analyze("https://stripe.com")
64
+ print(data["page_type"]) # "product landing page"
65
+ print(data["primary_cta"]) # "Start now"
66
+ print(data["technologies"]) # ["React", "Next.js", "Cloudflare"]
67
+
68
+ # URL → PDF
69
+ pdf = client.pdf("https://github.com", format="A4")
70
+ open("page.pdf", "wb").write(pdf)
71
+
72
+ # HTML → image (OG cards, email previews)
73
+ html = '<div style="background:#0d0d0f;color:#fff;padding:80px;font-size:48px">My OG Card</div>'
74
+ img = client.render(html, width=1200, height=630)
75
+ open("og-card.png", "wb").write(img)
76
+
77
+ # Batch (multiple URLs)
78
+ results = client.batch(["https://a.com", "https://b.com"], endpoint="metadata")
79
+ for r in results:
80
+ print(r["url"], r.get("title"))
81
+ ```
82
+
83
+ ## API Key
84
+
85
+ Get a free key (100 calls/month, no credit card) at **https://snapapi.tech**.
86
+
87
+ ```bash
88
+ export SNAPAPI_KEY=snap_your_key_here
89
+ ```
90
+
91
+ Or pass it directly: `client = SnapAPI(api_key="snap_your_key_here")`
92
+
93
+ ## Methods
94
+
95
+ | Method | Returns | Description |
96
+ |---|---|---|
97
+ | `screenshot(url, **kwargs)` | `bytes` | PNG/JPEG/WebP image |
98
+ | `metadata(url)` | `dict` | OG tags, title, favicon, canonical |
99
+ | `analyze(url, screenshot=False)` | `dict` | Page type, CTA, tech stack, + optional screenshot |
100
+ | `pdf(url, **kwargs)` | `bytes` | PDF binary |
101
+ | `render(html, **kwargs)` | `bytes` | HTML → image |
102
+ | `batch(urls, endpoint, params)` | `list[dict]` | Parallel multi-URL processing |
103
+
104
+ Full parameter reference: [snapapi.tech/docs](https://snapapi.tech/docs)
105
+
106
+ ## Requirements
107
+
108
+ - Python 3.8+
109
+ - No third-party dependencies
110
+
111
+ ## License
112
+
113
+ MIT
@@ -0,0 +1,76 @@
1
+ # snapapi-python
2
+
3
+ Python SDK for the [SnapAPI](https://snapapi.tech) web intelligence API. Zero dependencies — uses only the Python standard library.
4
+
5
+ ```bash
6
+ pip install snapapi-python
7
+ ```
8
+
9
+ ## Quick Start
10
+
11
+ ```python
12
+ from snapapi import SnapAPI
13
+
14
+ client = SnapAPI() # reads SNAPAPI_KEY from environment
15
+
16
+ # Screenshot
17
+ png = client.screenshot("https://github.com", full_page=True)
18
+ open("screenshot.png", "wb").write(png)
19
+
20
+ # Metadata
21
+ meta = client.metadata("https://github.com")
22
+ print(meta["og_title"]) # "GitHub: Let's build from here"
23
+ print(meta["og_image"]) # "https://..."
24
+
25
+ # Full page analysis
26
+ data = client.analyze("https://stripe.com")
27
+ print(data["page_type"]) # "product landing page"
28
+ print(data["primary_cta"]) # "Start now"
29
+ print(data["technologies"]) # ["React", "Next.js", "Cloudflare"]
30
+
31
+ # URL → PDF
32
+ pdf = client.pdf("https://github.com", format="A4")
33
+ open("page.pdf", "wb").write(pdf)
34
+
35
+ # HTML → image (OG cards, email previews)
36
+ html = '<div style="background:#0d0d0f;color:#fff;padding:80px;font-size:48px">My OG Card</div>'
37
+ img = client.render(html, width=1200, height=630)
38
+ open("og-card.png", "wb").write(img)
39
+
40
+ # Batch (multiple URLs)
41
+ results = client.batch(["https://a.com", "https://b.com"], endpoint="metadata")
42
+ for r in results:
43
+ print(r["url"], r.get("title"))
44
+ ```
45
+
46
+ ## API Key
47
+
48
+ Get a free key (100 calls/month, no credit card) at **https://snapapi.tech**.
49
+
50
+ ```bash
51
+ export SNAPAPI_KEY=snap_your_key_here
52
+ ```
53
+
54
+ Or pass it directly: `client = SnapAPI(api_key="snap_your_key_here")`
55
+
56
+ ## Methods
57
+
58
+ | Method | Returns | Description |
59
+ |---|---|---|
60
+ | `screenshot(url, **kwargs)` | `bytes` | PNG/JPEG/WebP image |
61
+ | `metadata(url)` | `dict` | OG tags, title, favicon, canonical |
62
+ | `analyze(url, screenshot=False)` | `dict` | Page type, CTA, tech stack, + optional screenshot |
63
+ | `pdf(url, **kwargs)` | `bytes` | PDF binary |
64
+ | `render(html, **kwargs)` | `bytes` | HTML → image |
65
+ | `batch(urls, endpoint, params)` | `list[dict]` | Parallel multi-URL processing |
66
+
67
+ Full parameter reference: [snapapi.tech/docs](https://snapapi.tech/docs)
68
+
69
+ ## Requirements
70
+
71
+ - Python 3.8+
72
+ - No third-party dependencies
73
+
74
+ ## License
75
+
76
+ MIT
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,51 @@
1
+ """
2
+ Minimal setuptools config for snapapi-python.
3
+
4
+ Install from source:
5
+ pip install .
6
+
7
+ Install in editable/dev mode:
8
+ pip install -e .
9
+
10
+ Publish to PyPI:
11
+ python setup.py sdist bdist_wheel
12
+ twine upload dist/*
13
+ """
14
+
15
+ from setuptools import setup
16
+
17
+ with open("README.md", "r", encoding="utf-8") as f:
18
+ long_description = f.read()
19
+
20
+ setup(
21
+ name="snapapi-python",
22
+ version="0.1.1",
23
+ description="Python SDK for the SnapAPI web intelligence API — screenshots, metadata, PDF, page analysis",
24
+ long_description=long_description,
25
+ long_description_content_type="text/markdown",
26
+ author="SnapAPI",
27
+ author_email="hello@snapapi.tech",
28
+ url="https://snapapi.tech",
29
+ project_urls={
30
+ "Documentation": "https://snapapi.tech/docs",
31
+ "Source": "https://github.com/Boehner/snapapi-python",
32
+ "Bug Tracker": "https://github.com/Boehner/snapapi-python/issues",
33
+ },
34
+ py_modules=["snapapi"],
35
+ python_requires=">=3.8",
36
+ classifiers=[
37
+ "Development Status :: 3 - Alpha",
38
+ "Intended Audience :: Developers",
39
+ "License :: OSI Approved :: MIT License",
40
+ "Programming Language :: Python :: 3",
41
+ "Programming Language :: Python :: 3.8",
42
+ "Programming Language :: Python :: 3.9",
43
+ "Programming Language :: Python :: 3.10",
44
+ "Programming Language :: Python :: 3.11",
45
+ "Programming Language :: Python :: 3.12",
46
+ "Topic :: Internet :: WWW/HTTP",
47
+ "Topic :: Software Development :: Libraries :: Python Modules",
48
+ ],
49
+ keywords="screenshot api web-scraping metadata pdf puppeteer snapapi",
50
+ license="MIT",
51
+ )
@@ -0,0 +1,437 @@
1
+ """
2
+ SnapAPI Python SDK
3
+ ==================
4
+ A minimal, zero-dependency Python client for the SnapAPI web intelligence API.
5
+ Uses only the Python standard library (urllib, json, os).
6
+
7
+ Install:
8
+ pip install snapapi-python
9
+ # or: python setup.py install
10
+
11
+ Usage:
12
+ from snapapi import SnapAPI
13
+
14
+ client = SnapAPI() # reads SNAPAPI_KEY from env
15
+ # or
16
+ client = SnapAPI(api_key="snap_xxxxxxxx") # explicit key
17
+
18
+ png_bytes = client.screenshot("https://github.com")
19
+ metadata = client.metadata("https://github.com")
20
+ analysis = client.analyze("https://github.com", screenshot=True)
21
+ pdf_bytes = client.pdf("https://github.com", format="A4")
22
+ img_bytes = client.render("<h1>Hello</h1>", width=1200, height=630)
23
+ results = client.batch(["https://a.com", "https://b.com"])
24
+
25
+ Docs: https://snapapi.tech/docs
26
+ """
27
+
28
+ import json
29
+ import os
30
+ import urllib.error
31
+ import urllib.parse
32
+ import urllib.request
33
+ from typing import Any, Dict, List, Optional
34
+
35
+ __version__ = "0.1.1"
36
+ __all__ = ["SnapAPI", "SnapAPIError"]
37
+
38
+ _BASE_URL = "https://snapapi.tech"
39
+
40
+
41
+ class SnapAPIError(Exception):
42
+ """Raised when the SnapAPI returns an error response."""
43
+
44
+ def __init__(self, status: int, message: str) -> None:
45
+ self.status = status
46
+ self.message = message
47
+ super().__init__(f"SnapAPI error {status}: {message}")
48
+
49
+
50
+ class SnapAPI:
51
+ """
52
+ Client for the SnapAPI web intelligence API.
53
+
54
+ Parameters
55
+ ----------
56
+ api_key : str, optional
57
+ Your SnapAPI API key. If omitted, the value of the
58
+ ``SNAPAPI_KEY`` environment variable is used.
59
+ base_url : str, optional
60
+ Override the default API base URL (useful for self-hosted installs).
61
+ timeout : int, optional
62
+ Request timeout in seconds. Defaults to 45.
63
+ """
64
+
65
+ def __init__(
66
+ self,
67
+ api_key: Optional[str] = None,
68
+ base_url: str = _BASE_URL,
69
+ timeout: int = 45,
70
+ ) -> None:
71
+ self._api_key = api_key or os.environ.get("SNAPAPI_KEY", "")
72
+ if not self._api_key:
73
+ raise SnapAPIError(
74
+ 0,
75
+ "No API key provided. Set SNAPAPI_KEY env var or pass api_key= to SnapAPI().\n"
76
+ "Get a free key at https://snapapi.tech",
77
+ )
78
+ self._base_url = base_url.rstrip("/")
79
+ self._timeout = timeout
80
+
81
+ # ── Internal helpers ──────────────────────────────────────────────────────
82
+
83
+ def _get(self, path: str, params: Dict[str, Any]) -> bytes:
84
+ """Make a GET request; return raw response bytes."""
85
+ qs = urllib.parse.urlencode(
86
+ {k: str(v) for k, v in params.items() if v is not None}
87
+ )
88
+ url = f"{self._base_url}{path}?{qs}"
89
+ req = urllib.request.Request(url, headers={"x-api-key": self._api_key})
90
+ try:
91
+ with urllib.request.urlopen(req, timeout=self._timeout) as resp:
92
+ return resp.read()
93
+ except urllib.error.HTTPError as exc:
94
+ body = exc.read().decode("utf-8", errors="replace")
95
+ try:
96
+ msg = json.loads(body).get("error", body)
97
+ except Exception:
98
+ msg = body
99
+ raise SnapAPIError(exc.code, msg) from exc
100
+
101
+ def _get_json(self, path: str, params: Dict[str, Any]) -> Dict[str, Any]:
102
+ """Make a GET request; parse and return JSON dict."""
103
+ raw = self._get(path, params)
104
+ try:
105
+ return json.loads(raw)
106
+ except json.JSONDecodeError as exc:
107
+ raise SnapAPIError(0, f"Invalid JSON response: {raw[:200]}") from exc
108
+
109
+ def _post_json(self, path: str, payload: Dict[str, Any]) -> bytes:
110
+ """Make a POST request with a JSON body; return raw response bytes."""
111
+ body = json.dumps(payload).encode("utf-8")
112
+ url = f"{self._base_url}{path}"
113
+ req = urllib.request.Request(
114
+ url,
115
+ data=body,
116
+ headers={
117
+ "x-api-key": self._api_key,
118
+ "Content-Type": "application/json",
119
+ "Content-Length": str(len(body)),
120
+ },
121
+ method="POST",
122
+ )
123
+ try:
124
+ with urllib.request.urlopen(req, timeout=self._timeout) as resp:
125
+ return resp.read()
126
+ except urllib.error.HTTPError as exc:
127
+ body_str = exc.read().decode("utf-8", errors="replace")
128
+ try:
129
+ msg = json.loads(body_str).get("error", body_str)
130
+ except Exception:
131
+ msg = body_str
132
+ raise SnapAPIError(exc.code, msg) from exc
133
+
134
+ # ── Public API ────────────────────────────────────────────────────────────
135
+
136
+ def screenshot(
137
+ self,
138
+ url: str,
139
+ *,
140
+ format: str = "png",
141
+ width: int = 1280,
142
+ height: int = 800,
143
+ full_page: bool = False,
144
+ dark_mode: bool = False,
145
+ device: Optional[str] = None,
146
+ selector: Optional[str] = None,
147
+ delay: Optional[int] = None,
148
+ ) -> bytes:
149
+ """
150
+ Capture a screenshot of *url*.
151
+
152
+ Parameters
153
+ ----------
154
+ url : str
155
+ The page to capture.
156
+ format : str
157
+ Output format: ``"png"``, ``"jpeg"``, or ``"webp"``.
158
+ width : int
159
+ Viewport width in pixels.
160
+ height : int
161
+ Viewport height in pixels.
162
+ full_page : bool
163
+ Capture the full scrollable page.
164
+ dark_mode : bool
165
+ Render with ``prefers-color-scheme: dark``.
166
+ device : str, optional
167
+ Device preset, e.g. ``"iphone14"``, ``"pixel7"``, ``"ipad"``.
168
+ selector : str, optional
169
+ CSS selector — capture only that element.
170
+ delay : int, optional
171
+ Extra milliseconds to wait before capturing.
172
+
173
+ Returns
174
+ -------
175
+ bytes
176
+ Raw image bytes (PNG/JPEG/WebP).
177
+ """
178
+ params: Dict[str, Any] = dict(
179
+ url=url,
180
+ format=format,
181
+ width=width,
182
+ height=height,
183
+ full_page=str(full_page).lower(),
184
+ dark_mode=str(dark_mode).lower(),
185
+ )
186
+ if device is not None:
187
+ params["device"] = device
188
+ if selector is not None:
189
+ params["selector"] = selector
190
+ if delay is not None:
191
+ params["delay"] = delay
192
+
193
+ return self._get("/v1/screenshot", params)
194
+
195
+ def metadata(self, url: str) -> Dict[str, Any]:
196
+ """
197
+ Extract metadata from *url*.
198
+
199
+ Returns a dict with keys:
200
+ ``url``, ``title``, ``description``, ``og_title``, ``og_description``,
201
+ ``og_image``, ``og_type``, ``favicon``, ``canonical``, ``language``.
202
+
203
+ Parameters
204
+ ----------
205
+ url : str
206
+ The page to extract metadata from.
207
+
208
+ Returns
209
+ -------
210
+ dict
211
+ """
212
+ return self._get_json("/v1/metadata", {"url": url})
213
+
214
+ def analyze(
215
+ self,
216
+ url: str,
217
+ *,
218
+ screenshot: bool = False,
219
+ ) -> Dict[str, Any]:
220
+ """
221
+ Full page analysis of *url*.
222
+
223
+ Returns page_type, primary_cta, nav_items, technologies, word_count,
224
+ load_time_ms, OG metadata, and (optionally) a base64 screenshot.
225
+
226
+ Parameters
227
+ ----------
228
+ url : str
229
+ The page to analyze.
230
+ screenshot : bool
231
+ Include a base64-encoded screenshot in the response.
232
+
233
+ Returns
234
+ -------
235
+ dict
236
+ """
237
+ params: Dict[str, Any] = {"url": url}
238
+ if screenshot:
239
+ params["screenshot"] = "true"
240
+ return self._get_json("/v1/analyze", params)
241
+
242
+ def pdf(
243
+ self,
244
+ url: str,
245
+ *,
246
+ format: str = "A4",
247
+ landscape: bool = False,
248
+ margin_top: int = 20,
249
+ margin_bottom: int = 20,
250
+ margin_left: int = 20,
251
+ margin_right: int = 20,
252
+ print_background: bool = True,
253
+ scale: float = 1.0,
254
+ delay: Optional[int] = None,
255
+ ) -> bytes:
256
+ """
257
+ Convert *url* to a PDF.
258
+
259
+ Parameters
260
+ ----------
261
+ url : str
262
+ The page to convert.
263
+ format : str
264
+ Paper format: ``"A4"``, ``"Letter"``, ``"A3"``, ``"A5"``, ``"Legal"``.
265
+ landscape : bool
266
+ Landscape orientation.
267
+ margin_top / margin_bottom / margin_left / margin_right : int
268
+ Margins in pixels.
269
+ print_background : bool
270
+ Print CSS background colors and images.
271
+ scale : float
272
+ Page scale (0.1–2.0).
273
+ delay : int, optional
274
+ Extra milliseconds to wait before generating.
275
+
276
+ Returns
277
+ -------
278
+ bytes
279
+ Raw PDF bytes.
280
+ """
281
+ params: Dict[str, Any] = dict(
282
+ url=url,
283
+ format=format,
284
+ landscape=str(landscape).lower(),
285
+ margin_top=margin_top,
286
+ margin_bottom=margin_bottom,
287
+ margin_left=margin_left,
288
+ margin_right=margin_right,
289
+ print_background=str(print_background).lower(),
290
+ scale=scale,
291
+ )
292
+ if delay is not None:
293
+ params["delay"] = delay
294
+ return self._get("/v1/pdf", params)
295
+
296
+ def render(
297
+ self,
298
+ html: str,
299
+ *,
300
+ width: int = 1200,
301
+ height: int = 630,
302
+ format: str = "png",
303
+ ) -> bytes:
304
+ """
305
+ Render raw *html* to a pixel-perfect image.
306
+
307
+ Ideal for OG cards, email previews, certificate images.
308
+
309
+ Parameters
310
+ ----------
311
+ html : str
312
+ Full HTML string to render.
313
+ width : int
314
+ Viewport width in pixels.
315
+ height : int
316
+ Viewport height in pixels.
317
+ format : str
318
+ Output format: ``"png"``, ``"jpeg"``, or ``"webp"``.
319
+
320
+ Returns
321
+ -------
322
+ bytes
323
+ Raw image bytes.
324
+ """
325
+ payload = {"html": html, "width": width, "height": height, "format": format}
326
+ return self._post_json("/v1/render", payload)
327
+
328
+ def batch(
329
+ self,
330
+ urls: List[str],
331
+ *,
332
+ endpoint: str = "screenshot",
333
+ params: Optional[Dict[str, Any]] = None,
334
+ ) -> List[Dict[str, Any]]:
335
+ """
336
+ Process multiple URLs in parallel.
337
+
338
+ Parameters
339
+ ----------
340
+ urls : list[str]
341
+ List of URLs to process.
342
+ endpoint : str
343
+ Which endpoint to call per URL: ``"screenshot"``, ``"metadata"``,
344
+ or ``"analyze"``.
345
+ params : dict, optional
346
+ Extra parameters to pass to each per-URL call.
347
+
348
+ Returns
349
+ -------
350
+ list[dict]
351
+ One result dict per URL. Each has ``status`` (``"ok"`` or
352
+ ``"error"``), ``url``, and endpoint-specific fields.
353
+
354
+ Raises
355
+ ------
356
+ SnapAPIError
357
+ If the batch request itself fails (not per-URL errors).
358
+ """
359
+ payload: Dict[str, Any] = {
360
+ "urls": urls,
361
+ "endpoint": endpoint,
362
+ }
363
+ if params:
364
+ payload["params"] = params
365
+
366
+ raw = self._post_json("/v1/batch", payload)
367
+ try:
368
+ data = json.loads(raw)
369
+ except json.JSONDecodeError as exc:
370
+ raise SnapAPIError(0, f"Invalid JSON in batch response: {raw[:200]}") from exc
371
+
372
+ return data.get("results", [])
373
+
374
+
375
+ # ── CLI / demo ────────────────────────────────────────────────────────────────
376
+
377
+ if __name__ == "__main__":
378
+ import sys
379
+
380
+ print("SnapAPI Python SDK — demo\n")
381
+
382
+ client = SnapAPI() # requires SNAPAPI_KEY in environment
383
+
384
+ target = sys.argv[1] if len(sys.argv) > 1 else "https://github.com"
385
+
386
+ # 1. Screenshot
387
+ print(f"[1] Screenshot of {target}...")
388
+ png = client.screenshot(target, full_page=False)
389
+ with open("demo_screenshot.png", "wb") as f:
390
+ f.write(png)
391
+ print(f" Saved demo_screenshot.png ({len(png) // 1024} KB)")
392
+
393
+ # 2. Metadata
394
+ print(f"\n[2] Metadata for {target}...")
395
+ meta = client.metadata(target)
396
+ print(f" Title: {meta.get('title', '')[:60]}")
397
+ print(f" OG image: {meta.get('og_image', '(none)')[:80]}")
398
+
399
+ # 3. Analyze
400
+ print(f"\n[3] Page analysis for {target}...")
401
+ analysis = client.analyze(target)
402
+ print(f" Page type: {analysis.get('page_type', '')}")
403
+ print(f" Primary CTA: {analysis.get('primary_cta', '')}")
404
+ print(f" Tech stack: {', '.join(analysis.get('technologies', []))}")
405
+
406
+ # 4. PDF
407
+ print(f"\n[4] PDF of {target}...")
408
+ pdf = client.pdf(target, format="A4")
409
+ with open("demo.pdf", "wb") as f:
410
+ f.write(pdf)
411
+ print(f" Saved demo.pdf ({len(pdf) // 1024} KB)")
412
+
413
+ # 5. Render HTML → image
414
+ print("\n[5] Render HTML to PNG...")
415
+ html = """
416
+ <div style="background:#1a1a2e;color:#f0f0f4;font-family:sans-serif;
417
+ padding:80px;width:1200px;height:630px;
418
+ display:flex;align-items:center;font-size:48px;font-weight:800;">
419
+ Hello from SnapAPI Python SDK
420
+ </div>"""
421
+ img = client.render(html, width=1200, height=630)
422
+ with open("demo_render.png", "wb") as f:
423
+ f.write(img)
424
+ print(f" Saved demo_render.png ({len(img) // 1024} KB)")
425
+
426
+ # 6. Batch
427
+ print(f"\n[6] Batch metadata for 2 URLs...")
428
+ results = client.batch(
429
+ ["https://github.com", "https://example.com"],
430
+ endpoint="metadata",
431
+ )
432
+ for r in results:
433
+ status = r.get("status", "?")
434
+ title = r.get("title", "")[:50]
435
+ print(f" {status:5s} {r.get('url', '')} → {title}")
436
+
437
+ print("\nDone. Check the generated files.")
@@ -0,0 +1,113 @@
1
+ Metadata-Version: 2.2
2
+ Name: snapapi-python
3
+ Version: 0.1.1
4
+ Summary: Python SDK for the SnapAPI web intelligence API — screenshots, metadata, PDF, page analysis
5
+ Home-page: https://snapapi.tech
6
+ Author: SnapAPI
7
+ Author-email: hello@snapapi.tech
8
+ License: MIT
9
+ Project-URL: Documentation, https://snapapi.tech/docs
10
+ Project-URL: Source, https://github.com/Boehner/snapapi-python
11
+ Project-URL: Bug Tracker, https://github.com/Boehner/snapapi-python/issues
12
+ Keywords: screenshot api web-scraping metadata pdf puppeteer snapapi
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.8
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Topic :: Internet :: WWW/HTTP
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Requires-Python: >=3.8
25
+ Description-Content-Type: text/markdown
26
+ Dynamic: author
27
+ Dynamic: author-email
28
+ Dynamic: classifier
29
+ Dynamic: description
30
+ Dynamic: description-content-type
31
+ Dynamic: home-page
32
+ Dynamic: keywords
33
+ Dynamic: license
34
+ Dynamic: project-url
35
+ Dynamic: requires-python
36
+ Dynamic: summary
37
+
38
+ # snapapi-python
39
+
40
+ Python SDK for the [SnapAPI](https://snapapi.tech) web intelligence API. Zero dependencies — uses only the Python standard library.
41
+
42
+ ```bash
43
+ pip install snapapi-python
44
+ ```
45
+
46
+ ## Quick Start
47
+
48
+ ```python
49
+ from snapapi import SnapAPI
50
+
51
+ client = SnapAPI() # reads SNAPAPI_KEY from environment
52
+
53
+ # Screenshot
54
+ png = client.screenshot("https://github.com", full_page=True)
55
+ open("screenshot.png", "wb").write(png)
56
+
57
+ # Metadata
58
+ meta = client.metadata("https://github.com")
59
+ print(meta["og_title"]) # "GitHub: Let's build from here"
60
+ print(meta["og_image"]) # "https://..."
61
+
62
+ # Full page analysis
63
+ data = client.analyze("https://stripe.com")
64
+ print(data["page_type"]) # "product landing page"
65
+ print(data["primary_cta"]) # "Start now"
66
+ print(data["technologies"]) # ["React", "Next.js", "Cloudflare"]
67
+
68
+ # URL → PDF
69
+ pdf = client.pdf("https://github.com", format="A4")
70
+ open("page.pdf", "wb").write(pdf)
71
+
72
+ # HTML → image (OG cards, email previews)
73
+ html = '<div style="background:#0d0d0f;color:#fff;padding:80px;font-size:48px">My OG Card</div>'
74
+ img = client.render(html, width=1200, height=630)
75
+ open("og-card.png", "wb").write(img)
76
+
77
+ # Batch (multiple URLs)
78
+ results = client.batch(["https://a.com", "https://b.com"], endpoint="metadata")
79
+ for r in results:
80
+ print(r["url"], r.get("title"))
81
+ ```
82
+
83
+ ## API Key
84
+
85
+ Get a free key (100 calls/month, no credit card) at **https://snapapi.tech**.
86
+
87
+ ```bash
88
+ export SNAPAPI_KEY=snap_your_key_here
89
+ ```
90
+
91
+ Or pass it directly: `client = SnapAPI(api_key="snap_your_key_here")`
92
+
93
+ ## Methods
94
+
95
+ | Method | Returns | Description |
96
+ |---|---|---|
97
+ | `screenshot(url, **kwargs)` | `bytes` | PNG/JPEG/WebP image |
98
+ | `metadata(url)` | `dict` | OG tags, title, favicon, canonical |
99
+ | `analyze(url, screenshot=False)` | `dict` | Page type, CTA, tech stack, + optional screenshot |
100
+ | `pdf(url, **kwargs)` | `bytes` | PDF binary |
101
+ | `render(html, **kwargs)` | `bytes` | HTML → image |
102
+ | `batch(urls, endpoint, params)` | `list[dict]` | Parallel multi-URL processing |
103
+
104
+ Full parameter reference: [snapapi.tech/docs](https://snapapi.tech/docs)
105
+
106
+ ## Requirements
107
+
108
+ - Python 3.8+
109
+ - No third-party dependencies
110
+
111
+ ## License
112
+
113
+ MIT
@@ -0,0 +1,7 @@
1
+ README.md
2
+ setup.py
3
+ snapapi.py
4
+ snapapi_python.egg-info/PKG-INFO
5
+ snapapi_python.egg-info/SOURCES.txt
6
+ snapapi_python.egg-info/dependency_links.txt
7
+ snapapi_python.egg-info/top_level.txt