fix: book canonical, fr/de pin warnings, pin grouping per locale, SEO checks
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
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
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5a9fe676fc
commit
fe1802f818
67 files changed
+11875
-9596
No files matched your search
Executable
+75
@@ -0,0 +1,75 @@
|
||||
#!/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)
|
||||
Reference in new issue
Block a user