Files
ESPDocs/scripts/verifica-seo.py
T
Lucas RayanandClaude Sonnet 5.5 fe1802f818
CI / Lint e auditorias (push) Successful in 48s
CI / Trivy (dependências e segredos) (push) Successful in 12s
CI / Imagem Docker (linux/arm64) (push) Successful in 3m41s
Release / Plano (reaproveitar a imagem?) (push) Successful in 6s
Release / ci (push) Skipped
Release / Publica a imagem (linux/arm64) (push) Successful in 16s
Release / Cria a release no Gitea (push) Successful in 6s
fix: book canonical, fr/de pin warnings, pin grouping per locale, SEO checks
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 23:58:11 -03:00

76 lines
2.7 KiB
Python
Executable File

#!/usr/bin/env python3
"""Confere canonical, hreflang e <html lang> de todas as URLs do sitemap.
python3 scripts/verifica-seo.py http://127.0.0.1:3998
Regras: o canonical é a própria URL; o conjunto de hreflang da página é o mesmo
do sitemap; há x-default quando existe mais de um idioma; o livro (só em pt)
não aponta para outros idiomas. Cada falha é impressa e o script sai com 1.
"""
import re
import sys
import urllib.request
from urllib.parse import urlparse
base = sys.argv[1].rstrip("/")
LANG = {"pt": "pt-BR", "en": "en", "es": "es-419", "fr": "fr", "de": "de", "zh-CN": "zh-CN"}
def get(url):
req = urllib.request.Request(url, headers={"User-Agent": "ESPDocs-SmokeTest/1.0"})
return urllib.request.urlopen(req, timeout=15).read().decode("utf-8")
def caminho(u):
return urlparse(u).path or "/"
sitemap = get(base + "/sitemap.xml")
falhas = 0
total = 0
for bloco in re.findall(r"<url>(.*?)</url>", sitemap, re.S):
loc = caminho(re.search(r"<loc>([^<]+)</loc>", bloco).group(1))
esperado = {
h: caminho(u)
for h, u in re.findall(r'<xhtml:link rel="alternate" hreflang="([^"]+)" href="([^"]+)"', bloco)
}
total += 1
try:
html = get(base + loc)
except Exception as e:
print(f"FALHOU {loc}: {e}")
falhas += 1
continue
head = html.split("</head>")[0]
idioma = loc.strip("/").split("/")[0]
m = re.search(r'<html[^>]*\blang="([^"]+)"', html)
if not m or m.group(1) != LANG.get(idioma):
print(f"FALHOU {loc}: <html lang> é {m and m.group(1)}, esperado {LANG.get(idioma)}")
falhas += 1
canon = re.search(r'<link rel="canonical" href="([^"]+)"', head)
if not canon or caminho(canon.group(1)) != loc:
print(f"FALHOU {loc}: canonical é {canon and caminho(canon.group(1))}")
falhas += 1
na_pagina = {
h: caminho(u)
for h, u in re.findall(r'<link rel="alternate" hrefLang="([^"]+)" href="([^"]+)"', head)
}
sem_default_pagina = {k: v for k, v in na_pagina.items() if k != "x-default"}
sem_default_sitemap = {k: v for k, v in esperado.items() if k != "x-default"}
if len(sem_default_sitemap) > 1 and sem_default_pagina != sem_default_sitemap:
print(f"FALHOU {loc}: hreflang da página difere do sitemap")
falhas += 1
if len(sem_default_sitemap) > 1 and "x-default" not in na_pagina:
print(f"FALHOU {loc}: sem x-default")
falhas += 1
if len(sem_default_sitemap) <= 1 and len(sem_default_pagina) > 1:
print(f"FALHOU {loc}: página de um idioma só com hreflang para outros: {sorted(sem_default_pagina)}")
falhas += 1
if falhas == 0:
print(f" ✔ SEO: canonical, hreflang e lang corretos em {total} URLs do sitemap.")
sys.exit(1 if falhas else 0)