Skip to content

Instantly share code, notes, and snippets.

@jadsongmatos
Last active June 13, 2025 14:49
Show Gist options
  • Save jadsongmatos/5dd89e48a0f9524131902ff0aaa5c730 to your computer and use it in GitHub Desktop.
Save jadsongmatos/5dd89e48a0f9524131902ff0aaa5c730 to your computer and use it in GitHub Desktop.
import os
import re
import base64
import hashlib
from bs4 import BeautifulSoup
def salvar_com_hash(conteudo_bytes, pasta_destino, extensao):
"""
Dado o conteúdo em bytes, calcula o hash e salva em `pasta_destino` com
nome <hash>.<extensao>.
Retorna o caminho relativo do arquivo que foi (ou já estava) gravado.
"""
hash_ = hashlib.md5(conteudo_bytes).hexdigest()
nome_arquivo = f"{hash_}.{extensao}"
caminho_arquivo = os.path.join(pasta_destino, nome_arquivo)
if not os.path.exists(caminho_arquivo):
with open(caminho_arquivo, "wb") as f:
f.write(conteudo_bytes)
return nome_arquivo
def substituir_recursos_css(texto, pasta_images, pasta_fonts):
"""
Substitui referências base64 por arquivos externos em textos CSS.
"""
def replace_img(match):
tipo = match.group(1)
b64_data = match.group(2)
extensao = tipo.replace("jpeg", "jpg")
if extensao.startswith("svg"):
extensao = "svg"
try:
img_bytes = base64.b64decode(b64_data)
except Exception as e:
print(f"Erro ao decodificar imagem CSS: {e}")
return match.group(0)
nome_arq = salvar_com_hash(img_bytes, pasta_images, extensao)
return f'url("images/{nome_arq}")'
texto = re.sub(
r'url\(\s*["\']?data:image/([^;]+);base64,([^"\'()]+)["\']?\)',
replace_img,
texto,
flags=re.IGNORECASE
)
def replace_woff2(match):
b64_data = match.group(1)
try:
fonte_bytes = base64.b64decode(b64_data)
except Exception as e:
print(f"Erro ao decodificar fonte WOFF2: {e}")
return match.group(0)
nome_fonte = salvar_com_hash(fonte_bytes, pasta_fonts, "woff2")
return f'url("fonts/{nome_fonte}")'
texto = re.sub(
r'url\(\s*["\']?data:(?:font/woff2|application/font-woff2);base64,([^"\'()]+)["\']?\)',
replace_woff2,
texto,
flags=re.IGNORECASE
)
return texto
def processar_html(caminho_arquivo, pasta_base):
"""
Processa um único arquivo HTML: remove 'no-referrer', ajusta links e imagens, e salva recursos embutidos.
"""
pasta_images = os.path.join(pasta_base, "images")
pasta_fonts = os.path.join(pasta_base, "fonts")
pasta_js = os.path.join(pasta_base, "js")
pasta_css = os.path.join(pasta_base, "css")
os.makedirs(pasta_images, exist_ok=True)
os.makedirs(pasta_fonts, exist_ok=True)
os.makedirs(pasta_js, exist_ok=True)
os.makedirs(pasta_css, exist_ok=True)
with open(caminho_arquivo, "r", encoding="utf-8") as f:
conteudo = f.read()
soup = BeautifulSoup(conteudo, "html.parser")
# --- REMOVER <base href="..."> ---
for base_tag in soup.find_all("base"):
base_tag.decompose()
# --- REMOVER <meta http-equiv="..."> ---
for meta in soup.find_all("meta", attrs={"http-equiv": True}):
meta.decompose()
# Remover content="no-referrer" das tags <meta>
for meta in soup.find_all("meta", content="no-referrer"):
del meta["content"]
# Processar <img> com src em base64
for img in soup.find_all("img"):
src = img.get("src", "")
if src.startswith("data:image/"):
match = re.match(r"data:image/([^;]+);base64,(.*)", src, re.I)
if match:
tipo = match.group(1)
b64_data = match.group(2)
extensao = tipo.replace("jpeg", "jpg")
if extensao.startswith("svg"):
extensao = "svg"
try:
imagem_bytes = base64.b64decode(b64_data)
except Exception as e:
print(f"Erro ao decodificar imagem: {e}")
continue
nome_arquivo = salvar_com_hash(imagem_bytes, pasta_images, extensao)
img["src"] = f"images/{nome_arquivo}"
# Atualizar atributos style em todas as tags
for tag in soup.find_all(style=True):
estilo_antigo = tag["style"]
tag["style"] = substituir_recursos_css(estilo_antigo, pasta_images, pasta_fonts)
# Processar scripts inline - SEM SRC (normal e module)
scripts_inline = soup.find_all("script", src=False)
js_normal = []
js_module = []
for script in scripts_inline:
script_type = script.attrs.get("type", "").strip().lower()
if script.string:
conteudo_script = script.string.strip()
if not conteudo_script:
continue
if script_type == "module":
js_module.append(conteudo_script)
else:
js_normal.append(conteudo_script)
script.decompose()
# Salvar scripts normais
if js_normal:
js_total = "\n".join(js_normal).strip()
if js_total:
js_bytes = js_total.encode("utf-8")
nome_js = salvar_com_hash(js_bytes, pasta_js, "js")
nova_tag_script = soup.new_tag("script", src=f"js/{nome_js}")
if soup.body:
soup.body.append(nova_tag_script)
else:
soup.append(nova_tag_script)
# Salvar scripts modules
if js_module:
js_total = "\n".join(js_module).strip()
if js_total:
js_bytes = js_total.encode("utf-8")
nome_js = salvar_com_hash(js_bytes, pasta_js, "js")
nova_tag_script = soup.new_tag("script", src=f"js/{nome_js}", type="module")
if soup.body:
soup.body.append(nova_tag_script)
else:
soup.append(nova_tag_script)
# Processar scripts com src="data:..."
for script in soup.find_all("script", src=True):
src = script["src"]
if src.startswith("data:"):
# Exemplo: data:module;base64,BASE64AQUI
match = re.match(r"data:[^,]*;base64,([^,]*)", src)
if match:
b64_data = match.group(1)
try:
js_content = base64.b64decode(b64_data).decode("utf-8")
except Exception as e:
print(f"Erro ao decodificar script base64: {e}")
continue
js_bytes = js_content.encode("utf-8")
nome_js = salvar_com_hash(js_bytes, pasta_js, "js")
# Criar novo script com caminho externo
new_script = soup.new_tag(
"script",
src=f"js/{nome_js}",
type=script.get("type", "text/javascript")
)
# Copiar atributos importantes
if script.has_attr("referrerpolicy"):
new_script["referrerpolicy"] = script["referrerpolicy"]
script.replace_with(new_script)
# Processar estilos internos <style>
for style in soup.find_all("style"):
if not style.string:
continue
css_conteudo = style.string
css_conteudo = substituir_recursos_css(css_conteudo, pasta_images, pasta_fonts)
css_bytes = css_conteudo.encode("utf-8")
if len(css_bytes) >= 4096:
nome_css = salvar_com_hash(css_bytes, pasta_css, "css")
nova_tag_link = soup.new_tag("link", rel="stylesheet", href=f"css/{nome_css}")
style.replace_with(nova_tag_link)
# Adicionar referrerpolicy="origin" onde aplicável
for tag in soup.find_all(["a", "img", "script", "link"]):
if tag.has_attr("href") or tag.has_attr("src"):
tag["referrerpolicy"] = "origin"
# Salva o HTML modificado
with open(caminho_arquivo, "w", encoding="utf-8") as f:
f.write(str(soup))
print(f"Processado: {caminho_arquivo}")
def processar_todos_html(pasta):
"""
Percorre todos os arquivos .html na pasta especificada e processa cada um.
"""
for arquivo in os.listdir(pasta):
if arquivo.lower().endswith(".html"):
caminho_arquivo = os.path.join(pasta, arquivo)
print(f"Processando: {caminho_arquivo}")
processar_html(caminho_arquivo, pasta)
print("Processamento concluído!")
if __name__ == "__main__":
caminho_da_pasta = "./html"
processar_todos_html(caminho_da_pasta)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment