Spaces:
Running
Running
File size: 4,952 Bytes
0cdb73b c11950c dbac20f c11950c dbac20f c11950c ba6e005 c11950c ba6e005 c11950c 59b0bed c11950c ba6e005 59b0bed c11950c dbac20f c11950c |
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 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
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 <title> tag.")
suggestions.append("Add a <title> 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 <meta name='description'> 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 <link rel='canonical'> to avoid duplicate content.")
# H1 Tag
h1_tags = soup.find_all("h1")
if len(h1_tags) != 1:
report.append(f"⚠️ Found {len(h1_tags)} <h1> tags.")
suggestions.append("Use exactly one <h1> 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()
|