import requests
from bs4 import BeautifulSoup
from urllib.parse import urlparse, urljoin
import gradio as gr
def seo_check(url):
report = []
suggestions = []
# Ensure HTTPS
if not url.startswith("http"):
url = "https://" + url
try:
response = requests.get(url, timeout=10)
response.raise_for_status()
html = response.text
except Exception as e:
return f"❌ Error accessing URL: {e}", ""
soup = BeautifulSoup(html, "html.parser")
# Title Tag
title = soup.title.string.strip() if soup.title else ""
if not title:
report.append("❌ Missing
tag.")
suggestions.append("Add a tag that describes your page in 50–60 characters.")
elif len(title) > 70:
report.append("⚠️ Title is too long.")
suggestions.append("Keep title under 70 characters.")
# Meta Description
desc_tag = soup.find("meta", attrs={"name": "description"})
desc = desc_tag["content"].strip() if desc_tag and desc_tag.get("content") else ""
if not desc:
report.append("❌ Missing meta description.")
suggestions.append("Add a summarizing the page.")
elif len(desc) > 160:
report.append("⚠️ Meta description is too long.")
suggestions.append("Keep meta descriptions under 160 characters.")
# Canonical Tag
canonical = soup.find("link", rel="canonical")
if not canonical:
report.append("❌ Missing canonical link.")
suggestions.append("Add a to avoid duplicate content.")
# H1 Tag
h1_tags = soup.find_all("h1")
if len(h1_tags) != 1:
report.append(f"⚠️ Found {len(h1_tags)}
tags.")
suggestions.append("Use exactly one
tag for SEO clarity.")
# Mobile viewport
viewport = soup.find("meta", attrs={"name": "viewport"})
if not viewport:
report.append("⚠️ No viewport meta tag.")
suggestions.append("Add a viewport meta tag for mobile responsiveness.")
# HTTPS check
if not url.startswith("https://"):
report.append("⚠️ URL is not secure (no HTTPS).")
suggestions.append("Install SSL and redirect HTTP to HTTPS.")
# Robots.txt and sitemap.xml
parsed = urlparse(url)
base = f"{parsed.scheme}://{parsed.netloc}"
robots_url = urljoin(base, "/robots.txt")
sitemap_url = urljoin(base, "/sitemap.xml")
try:
r1 = requests.get(robots_url)
if r1.status_code != 200:
report.append("❌ robots.txt not found.")
suggestions.append("Create a robots.txt to guide search bots.")
except:
report.append("❌ Could not access robots.txt.")
try:
r2 = requests.get(sitemap_url)
if r2.status_code != 200:
report.append("❌ sitemap.xml not found.")
suggestions.append("Add sitemap.xml for better crawling.")
except:
report.append("❌ Could not access sitemap.xml.")
# Open Graph Tags
og_title = soup.find("meta", property="og:title")
if not og_title:
report.append("⚠️ Missing Open Graph (og:title).")
suggestions.append("Add OG tags to improve sharing on social media.")
# Image alt text
images = soup.find_all("img")
alt_missing = [img for img in images if not img.get("alt")]
if alt_missing:
report.append(f"⚠️ {len(alt_missing)} images missing alt text.")
suggestions.append("Add descriptive alt attributes to all images.")
# Internal and external links
links = soup.find_all("a", href=True)
internal = 0
external = 0
for link in links:
href = link['href']
if parsed.netloc in href:
internal += 1
elif href.startswith("http"):
external += 1
report.append(f"ℹ️ Internal Links: {internal} | External Links: {external}")
suggestions.append("Ensure most important links are internal. Check broken links.")
# Keyword density (basic)
body_text = soup.get_text().lower()
words = body_text.split()
word_count = len(words)
keyword = parsed.netloc.replace("www.", "").split(".")[0]
keyword_freq = words.count(keyword)
density = (keyword_freq / word_count) * 100 if word_count else 0
report.append(f"ℹ️ Keyword '{keyword}' appears {keyword_freq} times ({density:.2f}% density)")
if density < 0.5:
suggestions.append("Consider using your main keyword more often (target 1–2%).")
return "\n".join(report), "\n".join(suggestions)
# Gradio UI
gr.Interface(
fn=seo_check,
inputs=gr.Textbox(label="Enter Website URL"),
outputs=[
gr.Textbox(label="SEO Report", lines=15),
gr.Textbox(label="Suggestions & Fixes", lines=15)
],
title="SEO Website Checker",
description="Analyze your website's SEO like Sitechecker.pro & SEOSiteCheckup, with clear solutions!"
).launch()