File size: 3,330 Bytes
2f927bc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
from fastapi import FastAPI, HTTPException, Query
from pydantic import BaseModel
from playwright.async_api import async_playwright
import asyncio
import base64
import time
from typing import Optional, List
import uvicorn
import logging

app = FastAPI()

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("analyzer")

class AnalysisResult(BaseModel):
    url: str
    load_time: float
    title: Optional[str]
    meta_description: Optional[str]
    og_image: Optional[str]
    seo_flags: List[str]
    accessibility_flags: List[str]
    screenshot_base64: str
    status_code: Optional[int] = None

@app.get("/analyze", response_model=AnalysisResult)
async def analyze_website(url: str):
    try:
        async with async_playwright() as p:
            browser = await p.chromium.launch(headless=True)
            context = await browser.new_context()
            page = await context.new_page()

            # Start timing
            start_time = time.time()
            response = await page.goto(url, timeout=60000, wait_until='domcontentloaded')
            await page.wait_for_load_state("networkidle")
            load_time = round(time.time() - start_time, 2)

            # Screenshot
            screenshot = await page.screenshot(full_page=True)
            screenshot_base64 = base64.b64encode(screenshot).decode("utf-8")

            # Title and meta info
            title = await page.title()
            meta_description = await page.eval_on_selector("meta[name='description']", "el => el.content") if await page.query_selector("meta[name='description']") else None
            og_image = await page.eval_on_selector("meta[property='og:image']", "el => el.content") if await page.query_selector("meta[property='og:image']") else None

            # SEO flags
            seo_flags = []
            if not title:
                seo_flags.append("Missing <title>")
            if not meta_description:
                seo_flags.append("Missing meta description")
            if not await page.query_selector("h1"):
                seo_flags.append("Missing <h1> tag")
            if not og_image:
                seo_flags.append("Missing Open Graph image")

            # Accessibility flags
            accessibility_flags = []
            images = await page.query_selector_all("img")
            for img in images:
                has_alt = await img.get_attribute("alt")
                if not has_alt:
                    accessibility_flags.append("Image without alt attribute")
                    break

            status_code = response.status if response else None

            await browser.close()

            return AnalysisResult(
                url=url,
                load_time=load_time,
                title=title,
                meta_description=meta_description,
                og_image=og_image,
                seo_flags=seo_flags,
                accessibility_flags=accessibility_flags,
                screenshot_base64=screenshot_base64,
                status_code=status_code
            )
    except Exception as e:
        logger.error(f"Analysis failed for {url}: {str(e)}")
        raise HTTPException(status_code=500, detail=f"Error analyzing {url}: {str(e)}")

if __name__ == "__main__":
    uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)