From 85dd29a457b1ce6d4495a82bfc931b89bca4a061 Mon Sep 17 00:00:00 2001 From: Bram Date: Fri, 27 Mar 2026 09:47:09 +0100 Subject: [PATCH] would be neat --- Dockers/puppeteer-api/README.md | 4 +++ .../__pycache__/browser.cpython-313.pyc | Bin 0 -> 6827 bytes Dockers/puppeteer-api/app/routes/browser.py | 27 +++++++++++++++++- .../__pycache__/browser.cpython-313.pyc | Bin 0 -> 27649 bytes Dockers/puppeteer-api/app/services/browser.py | 16 +++++++++++ 5 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 Dockers/puppeteer-api/app/routes/__pycache__/browser.cpython-313.pyc create mode 100644 Dockers/puppeteer-api/app/services/__pycache__/browser.cpython-313.pyc diff --git a/Dockers/puppeteer-api/README.md b/Dockers/puppeteer-api/README.md index d9b0c0a..3d91859 100644 --- a/Dockers/puppeteer-api/README.md +++ b/Dockers/puppeteer-api/README.md @@ -176,6 +176,7 @@ POSTGRES_PASSWORD= # PostgreSQL password (optional) ### Core Endpoints - `GET /` - Visit URL and get HTML content (with Cloudflare bypass) +- `GET /screenshot` - Capture a screenshot of a URL (PNG output) - `GET /seo` - Extract SEO information (with Cloudflare bypass) - `GET /meta` - Extract meta tags and Open Graph data (with Cloudflare bypass) - `GET /test-cloudflare` - Test Cloudflare bypass functionality on a specific URL @@ -198,6 +199,9 @@ POSTGRES_PASSWORD= # PostgreSQL password (optional) # Visit a URL curl -H "X-API-Key: your-api-key" "http://localhost:8000/?url=https://example.com" +# Capture a full-page screenshot (PNG) +curl -H "X-API-Key: your-api-key" "http://localhost:8000/screenshot?url=https://example.com" --output screenshot.png + # Extract SEO data curl -H "X-API-Key: your-api-key" "http://localhost:8000/seo?url=https://example.com" diff --git a/Dockers/puppeteer-api/app/routes/__pycache__/browser.cpython-313.pyc b/Dockers/puppeteer-api/app/routes/__pycache__/browser.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..22600c979c464b156433d74c54db8db4f124c7ff GIT binary patch literal 6827 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 literal 0 HcmV?d00001 diff --git a/Dockers/puppeteer-api/app/routes/browser.py b/Dockers/puppeteer-api/app/routes/browser.py index 2c08b78..987b1f6 100644 --- a/Dockers/puppeteer-api/app/routes/browser.py +++ b/Dockers/puppeteer-api/app/routes/browser.py @@ -1,10 +1,11 @@ -from fastapi import APIRouter, HTTPException, Header +from fastapi import APIRouter, HTTPException, Header, Response from typing import Optional from urllib.parse import unquote from app.config import API_KEY from app.database import get_cached_data, save_to_cache from app.services.browser import ( visit_url_service, + screenshot_url_service, extract_seo_service, extract_meta_tags_service, capture_outgoing_calls_service, @@ -41,6 +42,30 @@ async def visit_url(url: str, skipCache: bool = False, x_api_key: Optional[str] print(f"Error visiting URL {decoded_url}: {e}") raise HTTPException(status_code=500, detail=str(e)) +@router.get("/screenshot") +async def screenshot_url(url: str, fullPage: bool = True, x_api_key: Optional[str] = Header(None)): + """Capture a screenshot of a website and return it as PNG""" + if not x_api_key or x_api_key != API_KEY: + raise HTTPException(status_code=401, detail="Invalid API key") + + decoded_url = unquote(url) + + try: + result = await screenshot_url_service(decoded_url, fullPage) + + if isinstance(result, dict) and result.get("status") == "error": + raise HTTPException(status_code=500, detail=result.get("error", "Screenshot capture failed")) + + if not isinstance(result, (bytes, bytearray)): + raise HTTPException(status_code=500, detail="Unexpected screenshot response") + + return Response(content=result, media_type="image/png") + except HTTPException: + raise + except Exception as e: + print(f"Error taking screenshot for URL {decoded_url}: {e}") + raise HTTPException(status_code=500, detail=str(e)) + @router.get("/seo") async def extract_seo(url: str, skipCache: bool = False, x_api_key: Optional[str] = Header(None)): """Extract SEO information from a website""" diff --git a/Dockers/puppeteer-api/app/services/__pycache__/browser.cpython-313.pyc b/Dockers/puppeteer-api/app/services/__pycache__/browser.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a4ed96a519dbead4fc79b9ba35d24b24d06ab560 GIT binary patch literal 27649 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 MMwUx=(4_qT2ORFG0{{R3 literal 0 HcmV?d00001 diff --git a/Dockers/puppeteer-api/app/services/browser.py b/Dockers/puppeteer-api/app/services/browser.py index 22b0635..435d853 100644 --- a/Dockers/puppeteer-api/app/services/browser.py +++ b/Dockers/puppeteer-api/app/services/browser.py @@ -55,6 +55,22 @@ async def visit_url_service(decoded_url): # Perform the operation return await safe_browser_operation(decoded_url, visit_operation) +async def screenshot_url_service(decoded_url, full_page=True): + """Service function to visit a URL and return a screenshot as PNG bytes""" + print(f"Taking screenshot of: {decoded_url}") + + async def screenshot_operation(page): + try: + await page.goto(decoded_url, wait_until='networkidle', timeout=30000) + await page.wait_for_timeout(1000) + screenshot_bytes = await page.screenshot(full_page=full_page, type='png') + return screenshot_bytes + except Exception as e: + print(f"Error during screenshot capture: {e}") + return {"status": "error", "url": decoded_url, "error": str(e)} + + return await safe_browser_operation(decoded_url, screenshot_operation) + async def extract_seo_service(decoded_url): """Service function to extract SEO information from a website""" print(f"Extracting SEO from: {decoded_url}")