Por que automatizar relatórios SEO
Se você gasta mais de 2 horas por semana gerando relatórios manuais, está jogando tempo fora. Automatizar relatórios SEO com Python permite:
- Consistência: mesmo formato, mesmas métricas, toda semana
- Velocidade: de 2 horas para 30 segundos
- Histórico: dados armazenados automaticamente para comparação
- Escalabilidade: funciona para 1 ou 100 sites
Pré-requisitos
pip install google-api-python-client google-auth-oauthlib pandas
Configurar credenciais
- Acesse Google Cloud Console
- Crie um projeto novo
- Ative as APIs: Search Console API e Analytics Data API
- Crie credenciais OAuth 2.0 (tipo “Desktop app”)
- Baixe o
credentials.json
Script 1: Dados do Search Console
from googleapiclient.discovery import build
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
import pandas as pd
from datetime import datetime, timedelta
SCOPES = ['https://www.googleapis.com/auth/webmasters.readonly']
SITE_URL = 'https://seusite.com.br'
def autenticar():
flow = InstalledAppFlow.from_client_secrets_file(
'credentials.json', SCOPES
)
creds = flow.run_local_server(port=0)
return build('searchconsole', 'v1', credentials=creds)
def buscar_dados(service, dias=28):
end_date = datetime.now().strftime('%Y-%m-%d')
start_date = (datetime.now() - timedelta(days=dias)).strftime('%Y-%m-%d')
response = service.searchanalytics().query(
siteUrl=SITE_URL,
body={
'startDate': start_date,
'endDate': end_date,
'dimensions': ['query', 'page'],
'rowLimit': 1000,
'dimensionFilterGroups': [{
'filters': [{
'dimension': 'country',
'expression': 'bra'
}]
}]
}
).execute()
rows = response.get('rows', [])
data = []
for row in rows:
data.append({
'query': row['keys'][0],
'page': row['keys'][1],
'clicks': row['clicks'],
'impressions': row['impressions'],
'ctr': round(row['ctr'] * 100, 2),
'position': round(row['position'], 1),
})
return pd.DataFrame(data)
# Executar
service = autenticar()
df = buscar_dados(service)
df.to_csv(f'relatorio_seo_{datetime.now().strftime("%Y%m%d")}.csv', index=False)
print(f"Relatório gerado: {len(df)} linhas")
Script 2: Top páginas que estão caindo
def paginas_em_queda(service):
"""Compara últimos 7 dias com 7 dias anteriores"""
def get_period(start, end):
resp = service.searchanalytics().query(
siteUrl=SITE_URL,
body={
'startDate': start,
'endDate': end,
'dimensions': ['page'],
'rowLimit': 500,
}
).execute()
return {
row['keys'][0]: row['clicks']
for row in resp.get('rows', [])
}
today = datetime.now()
current = get_period(
(today - timedelta(days=7)).strftime('%Y-%m-%d'),
today.strftime('%Y-%m-%d')
)
previous = get_period(
(today - timedelta(days=14)).strftime('%Y-%m-%d'),
(today - timedelta(days=7)).strftime('%Y-%m-%d')
)
drops = []
for page, clicks in previous.items():
current_clicks = current.get(page, 0)
if clicks > 10 and current_clicks < clicks * 0.7:
drops.append({
'page': page,
'previous': clicks,
'current': current_clicks,
'drop': f"{((clicks - current_clicks) / clicks) * 100:.0f}%"
})
return sorted(drops, key=lambda x: x['previous'], reverse=True)
Script 3: Oportunidades (impressões altas, CTR baixo)
def encontrar_oportunidades(df):
"""Páginas com muitas impressões mas CTR baixo = oportunidade"""
oportunidades = df[
(df['impressions'] > 100) &
(df['ctr'] < 2.0) &
(df['position'] < 20)
].sort_values('impressions', ascending=False)
return oportunidades[['query', 'page', 'impressions', 'ctr', 'position']]
Script 4: Relatório em HTML
def gerar_relatorio_html(df, drops, oportunidades):
html = f"""
<html>
<head><style>
body {{ font-family: sans-serif; max-width: 800px; margin: 0 auto; }}
table {{ border-collapse: collapse; width: 100%; }}
th, td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
th {{ background: #1a1a2e; color: white; }}
.drop {{ color: red; font-weight: bold; }}
</style></head>
<body>
<h1>Relatório SEO — {datetime.now().strftime('%d/%m/%Y')}</h1>
<h2>Resumo</h2>
<p>Total de clicks: <b>{df['clicks'].sum():,}</b></p>
<p>Total de impressões: <b>{df['impressions'].sum():,}</b></p>
<p>CTR médio: <b>{df['ctr'].mean():.2f}%</b></p>
<h2>Páginas em queda</h2>
<table>
<tr><th>Página</th><th>Anterior</th><th>Atual</th><th>Queda</th></tr>
{''.join(f"<tr><td>{d['page']}</td><td>{d['previous']}</td><td>{d['current']}</td><td class='drop'>{d['drop']}</td></tr>" for d in drops[:10])}
</table>
<h2>Oportunidades (impressões altas, CTR baixo)</h2>
{oportunidades.head(15).to_html(index=False)}
</body>
</html>
"""
with open(f'relatorio_{datetime.now().strftime("%Y%m%d")}.html', 'w') as f:
f.write(html)
Agendamento com cron
# Executar todo domingo às 8h
0 8 * * 0 cd /home/user/seo-reports && python3 relatorio_seo.py >> cron.log 2>&1
Envio por email (opcional)
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
def enviar_email(html_content, destinatario):
msg = MIMEMultipart('alternative')
msg['Subject'] = f'Relatório SEO - {datetime.now().strftime("%d/%m/%Y")}'
msg['From'] = 'relatorios@seudominio.com'
msg['To'] = destinatario
msg.attach(MIMEText(html_content, 'html'))
with smtplib.SMTP_SSL('smtp.gmail.com', 465) as server:
server.login('seu@email.com', 'app_password')
server.send_message(msg)
Alternativas sem código
Se Python não é o seu forte:
| Ferramenta | Preço | Complexidade |
|---|---|---|
| Google Looker Studio | Grátis | Baixa |
| Screaming Frog | $259/ano | Média |
| SE Ranking | $65/mês | Baixa |
| Supermetrics | $99/mês | Média |
Automate the Boring Stuff with Python
O clássico sobre automação com Python. Perfeito para quem quer começar a automatizar tarefas repetitivas.
Ver na Amazon#anúncio · Link de afiliado Amazon. Ao comprar por este link, você apoia o site sem custo adicional.
Conclusão
Automatizar relatórios SEO com Python não é luxo — é necessidade para quem gerencia mais de 2 sites. Comece pelo Script 1 (dados brutos do Search Console), depois evolua para detecção de quedas e oportunidades. Em menos de um dia você monta um sistema que economiza horas toda semana.