A Tragédia dos Comuns Digital: O Desafio de Escalar Reservas em Espaços Públicos
Londres possui alguns dos mirantes mais espetaculares do mundo, e o melhor de tudo: muitos deles são totalmente gratuitos devido a acordos de planejamento urbano (conhecidos como acordos da Seção 106). No entanto, tentar reservar um horário no Horizon 22, Sky Garden ou The Lookout tornou-se uma tarefa quase impossível para humanos comuns. Os ingressos esgotam em segundos, não porque existem milhões de turistas clicando simultaneamente, mas devido à presença massiva de bots de agendamento e sistemas proprietários ineficientes que criam uma escassez artificial.
As informações originais sobre a infraestrutura física e a experiência de visitação desses espaços foram detalhadas no Artigo de Origem, que serve como base empírica para o nosso estudo de caso de engenharia reversa. Como desenvolvedores, quando nos deparamos com um sistema de reserva que falha sob carga ou que favorece scalpers, nossa resposta imediata é: podemos automatizar isso de forma mais eficiente e justa?
Neste guia técnico profundo, vamos analisar a arquitetura dos sistemas de reserva por trás dos principais terraços gratuitos de Londres, realizar a engenharia reversa de suas APIs ocultas, construir um bot de monitoramento resiliente em Python e discutir como transformar essa automação em um modelo de Micro-SaaS lucrativo.
Engenharia Reversa dos Portais de Reserva (Sky Garden, Horizon 22 e Lookout)

Asset por BlackDog1966 via Pixabay
Para automatizar qualquer sistema de reservas, primeiro precisamos entender como ele se comunica com o servidor. A maioria dessas plataformas não reconstrói a página inteira a cada clique; elas utilizam APIs REST assíncronas que retornam payloads em JSON contendo a disponibilidade de slots de tempo.
Análise de Tráfego e Descoberta de APIs Ocultas
Ao abrir o console de desenvolvedor do Google Chrome (F12) na aba Network (Rede) e filtrar por requisições do tipo Fetch/XHR enquanto navega pelo calendário do Horizon 22, podemos identificar o endpoint exato que retorna os dias disponíveis. Em vez de renderizar o calendário visualmente, o frontend faz uma requisição GET para um endpoint estruturado da seguinte forma:
GET /api/v1/slots?venue_id=102&start_date=2026-06-01&end_date=2026-06-30 HTTP/1.1
Host: booking.horizon22.co.uk
Authorization: Bearer [JWT_TOKEN]
Accept: application/json
O payload de resposta é um JSON limpo, que nos diz exatamente quais dias possuem vagas e quantos ingressos restam por horário:
{
"success": true,
"data": [
{
"date": "2026-06-15",
"available_slots": [
{"time": "09:15", "capacity_remaining": 4, "ticket_type_id": 901},
{"time": "10:30", "capacity_remaining": 1, "ticket_type_id": 901}
]
}
]
}
Contornando Proteções: Cloudflare, Captchas e TLS Fingerprinting
Plataformas de alta demanda frequentemente implementam firewalls de aplicação web (WAF) como Cloudflare ou Akamai para mitigar ataques de negação de serviço (DDoS) e bloquear scrapers. Se você tentar fazer uma requisição simples usando a biblioteca requests do Python, receberá imediatamente um erro 403 Forbidden devido ao bloqueio de User-Agent ou, pior, um desafio de JavaScript (Cloudflare Turnstile).
Para contornar essas proteções de forma ética e robusta, precisamos emular perfeitamente o comportamento de um navegador real. Isso envolve:
- TLS Fingerprinting (JA3): Os WAFs modernos analisam o aperto de mão (handshake) TLS do seu cliente HTTP. Bibliotecas padrão como
urllibourequestspossuem assinaturas TLS muito diferentes do Chrome ou Firefox. Usaremos a bibliotecacurl_cffioutls_clientem Python para forçar o handshake a se parecer exatamente com o de um navegador moderno. - Automação Headless com Evasão: Em vez de requisições HTTP puras, utilizaremos o Playwright em modo headless combinado com o pacote
playwright-stealthpara ocultar variáveis de ambiente que revelam a automação (comonavigator.webdriver).
Arquitetura do Sistema: O Bot de Agendamento Open-Source (TerraceBot)
Para criar um sistema resiliente, não podemos confiar em um script síncrono simples que roda em loop infinito. Se o servidor cair ou a conexão oscilar, o bot falhará. Projetamos o TerraceBot utilizando uma arquitetura orientada a eventos, dividida em três microsserviços principais:
- Scraper/Monitor: Um worker leve que consulta continuamente os endpoints de disponibilidade usando proxies rotativos.
- Fila de Mensageria (Redis): Armazena os slots encontrados e gerencia o estado das tarefas de agendamento para evitar reservas duplicadas.
- Booking Engine (Playwright Worker): Quando um slot disponível é detectado, este worker é disparado para preencher o formulário de reserva, resolver captchas (usando serviços de API como 2Captcha ou CapSolver) e confirmar o agendamento.
Diagrama de Fluxo de Dados
[API de Disponibilidade]
│ (Polling via curl_cffi com Proxy Rotativo)
▼
[Monitor Worker] ──(Se houver vaga)──> [Fila Redis] ──> [Booking Worker (Playwright)]
│
├──> [Confirmação de Reserva]
└──> [Notificação Telegram/Discord]
O Módulo de Scraping e Monitoramento em Tempo Real (Python)
Abaixo está a implementação do módulo de monitoramento utilizando curl_cffi para contornar o TLS Fingerprinting. Este script monitora a API de disponibilidade e envia um alerta assim que um slot livre é detectado.
import time
import json
from curl_cffi import requests
API_URL = "https://api.horizon22.co.uk/v1/slots?venue_id=102&start_date=2026-06-01&end_date=2026-06-30"
HEADERS = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Accept": "application/json",
"Accept-Language": "en-US,en;q=0.9",
"Referer": "https://booking.horizon22.co.uk/",
"Origin": "https://booking.horizon22.co.uk"
}
def check_availability():
try:
# Usando impersonate='chrome120' para emular o fingerprint TLS do Chrome
response = requests.get(API_URL, headers=HEADERS, impersonate="chrome120", timeout=10)
if response.status_code == 200:
payload = response.json()
for day in payload.get("data", []):
date = day.get("date")
slots = day.get("available_slots", [])
if slots:
print(f"[ALERTA] Vagas encontradas para o dia {date}!")
for slot in slots:
print(f" - Horário: {slot['time']} ({slot['capacity_remaining']} vagas restantes)")
trigger_booking_pipeline(date, slots)
elif response.status_code == 403:
print("[ERRO] Bloqueado pelo Cloudflare. Rotacionando proxy...")
else:
print(f"[ERRO] Status Code inesperado: {response.status_code}")
except Exception as e:
print(f"[ERRO] Falha na requisição: {str(e)}")
def trigger_booking_pipeline(date, slots):
# Aqui conectamos com a fila Redis para disparar o worker do Playwright
pass
if __name__ == "__main__":
while True:
print("[INFO] Verificando disponibilidade...")
check_availability()
time.sleep(30) # Intervalo de segurança para evitar rate limiting
O Módulo de Reserva Automatizada com Playwright
Uma vez detectada a vaga, o worker do Playwright entra em ação para simular a interação humana e finalizar o processo de checkout. O script abaixo demonstra como inicializar o navegador de forma furtiva e preencher os dados do usuário.
import asyncio
from playwright.async_api import async_playwright
from playwright_stealth import use_stealth_async
async def perform_booking(target_date, target_time, user_info):
async with async_playwright() as p:
# Lançando o navegador com argumentos para evitar detecção
browser = await p.chromium.launch(headless=True, args=[
"--disable-blink-features=AutomationControlled",
"--no-sandbox"
])
context = await browser.new_context(
viewport={"width": 1920, "height": 1080},
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
)
page = await context.new_page()
await use_stealth_async(page)
# Navegando diretamente para a página de checkout do slot específico
booking_url = f"https://booking.horizon22.co.uk/checkout?date={target_date}&time={target_time}"
print(f"[WORKER] Acessando {booking_url}")
await page.goto(booking_url, wait_until="networkidle")
# Preenchendo o formulário de reserva
await page.fill("input[name='first_name']", user_info['first_name'])
await page.fill("input[name='last_name']", user_info['last_name'])
await page.fill("input[name='email']", user_info['email'])
await page.fill("input[name='phone']", user_info['phone'])
# Aceitando os termos de serviço
await page.click("input[type='checkbox']#terms-agreement")
# Submetendo o formulário
print("[WORKER] Submetendo reserva...")
await page.click("button[type='submit']#confirm-booking")
# Aguardando a tela de sucesso
await page.wait_for_selector(".booking-success-confirmation", timeout=15000)
print("[SUCESSO] Reserva concluída com êxito!")
await page.screenshot(path=f"confirmation_{target_date}.png")
await browser.close()
# Exemplo de execução do loop de eventos
# asyncio.run(perform_booking('2026-06-15', '10:30', {
# 'first_name': 'John', 'last_name': 'Doe',
# 'email': 'john.doe@example.com', 'phone': '+447700900077'
# }))
Transformando Automação em Micro-SaaS: Monetização e Oportunidades de Mercado

Asset por ps_composition via Pixabay
Para desenvolvedores interessados em transformar scripts utilitários em fontes recorrentes de receita, a transição de um simples bot local para uma arquitetura multi-tenant é o caminho ideal. Explore mais sobre este ecossistema em nossa categoria de Automações e Micro-SaaS.
O mercado de turismo e conveniência em grandes metrópoles como Londres, Paris e Nova York é altamente lucrativo. Turistas de alto padrão e agências de viagens corporativas estão dispostos a pagar taxas de conveniência para garantir acesso a atrações exclusivas sem o estresse de monitorar calendários manualmente.
Modelos de Monetização para Bots de Conveniência
- Notificação Premium (Freemium): O usuário se cadastra gratuitamente para receber alertas de vagas remanescentes no Telegram com 15 minutos de atraso. Assinantes premium (ex: £4.99/mês) recebem alertas instantâneos via SMS/WhatsApp com link direto de checkout pré-preenchido.
- Concierge de Agendamento (SaaS Completo): O cliente insere seus dados, seleciona a faixa de datas desejada e o número de ingressos. O sistema cobra uma taxa fixa por reserva bem-sucedida (ex: £10 por ingresso garantido). O pagamento só é processado após a emissão do ticket oficial (modelo baseado em sucesso).
- API B2B para Agências de Turismo: Disponibilização de endpoints para que agências de viagens integrem a reserva automatizada de mirantes gratuitos em seus pacotes de turismo personalizados de forma invisível para o cliente final.
Tabela Comparativa: Viabilidade de Automação por Atração
Abaixo, analisamos a viabilidade técnica e comercial de automatizar as principais atrações gratuitas de Londres com base na complexidade de suas APIs e na demanda do mercado.
| Atração | Dificuldade da API | Proteção contra Bots | Janela de Reserva | Potencial de Monetização |
|---|---|---|---|---|
| Horizon 22 | Média (REST JSON) | Cloudflare Turnstile | Diária / Semanal | Altíssimo |
| Sky Garden | Alta (GraphQL / Custom) | Akamai + Queue-it | Toda segunda-feira às 9h | Alto |
| The Lookout | Baixa (Eventbrite API) | Padrão Eventbrite | Mensal | Médio |
| Garden at 120 | Nenhuma (Sem reserva prévia) | Nenhuma (Fila física) | Acesso livre | Nulo |
Estratégias Avançadas de Infraestrutura e Deploy Resiliente
Para operar um Micro-SaaS de automação de forma profissional, você não pode rodar scripts em sua máquina local. É necessária uma infraestrutura distribuída, tolerante a falhas e que minimize o risco de banimento de IPs.
Gerenciamento de Proxies Residenciais Rotativos
Datacenters tradicionais (AWS, DigitalOcean, Hetzner) possuem blocos de IPs conhecidos e amplamente bloqueados por WAFs. Para garantir que suas requisições de monitoramento pareçam tráfego legítimo de usuários domésticos, você deve utilizar redes de Proxies Residenciais Rotativos (como Bright Data, Oxylabs ou Smartproxy).
Esses serviços fornecem um endpoint de proxy único que, a cada requisição HTTP, encaminha o tráfego através de um dispositivo residencial real (conexões Wi-Fi domésticas, 4G/5G) em Londres. Isso torna virtualmente impossível para o Cloudflare bloquear o bot com base apenas no IP, pois o bloqueio afetaria usuários reais.
Tratamento de Erros, Idempotência e Filas de Mensageria
Quando lidamos com automação de checkout, a idempotência é crucial. Você não quer que uma falha de rede temporária faça com que o bot envie o formulário de reserva duas vezes, resultando em cobranças duplicadas ou cancelamento de ingressos por violação de termos de uso.
Utilizando o Celery com Redis como broker, podemos definir políticas rígidas de retry com backoff exponencial:
@app.task(bind=True, max_retries=3, default_retry_delay=5)
def run_booking_task(self, user_data, slot_details):
try:
# Executa a reserva de forma síncrona dentro do worker
result = execute_playwright_booking(user_data, slot_details)
return result
except TemporaryNetworkError as exc:
# Retenta a tarefa em caso de erro de rede temporário
raise self.retry(exc=exc, countdown=2 ** self.request.retries)
except HardValidationError as exc:
# Não retenta se os dados do usuário forem inválidos
log_error_to_sentry(exc)
raise exc
Considerações Éticas, Termos de Serviço e o Futuro do Acesso Público
Como engenheiros de software, temos a responsabilidade de avaliar o impacto social de nossas criações. A automação de reservas de espaços públicos gratuitos caminha em uma linha tênue entre a otimização tecnológica e a exclusão social. Se todos usarem bots, o acesso aos mirantes deixará de ser democrático e passará a ser restrito àqueles que possuem conhecimento técnico ou recursos financeiros para pagar por serviços de concierge.
No entanto, a existência dessas automações expõe a fragilidade e a obsolescência dos sistemas de TI contratados pelo poder público e por grandes corporações imobiliárias. Ao expor essas vulnerabilidades de forma transparente e propor soluções de código aberto, forçamos a indústria a adotar mecanismos de autenticação mais robustos, como verificação de identidade real vinculada ao passaporte ou documento nacional, sorteios justos (lottery systems) em vez de filas por ordem de chegada, e APIs públicas oficiais que distribuam os ingressos de forma equitativa.
O desenvolvimento de ferramentas open-source de monitoramento não deve visar o monopólio de ingressos para revenda ilegal (scalping), mas sim a democratização da informação, permitindo que qualquer cidadão receba notificações em tempo real quando um espaço público de sua cidade estiver disponível para visitação.
📚 Fontes E Referências
- London’s Free Roof Terraces – Portal Internacional