# Integração com Smiles (GOL) - Documentação Técnica ## ⚠️ AVISOS LEGAIS IMPORTANTES ### Limitações e Considerações 1. **API Não Pública** - O Smiles (GOL) NÃO possui uma API pública oficial - Todos os endpoints são de uso interno - Não há documentação oficial para desenvolvedores - O acesso pode ser bloqueado a qualquer momento 2. **Termos de Serviço** - O uso de scraping ou engenharia reversa pode violar os Termos de Serviço - Use APENAS para fins educacionais e pessoais - NÃO use para fins comerciais - NÃO sobrecarregue os servidores com muitas requisições 3. **Responsabilidade** - Você é responsável pelo uso deste código - O desenvolvedor não se responsabiliza por bloqueios ou problemas - Consulte um advogado antes de usar em produção ## 🔍 O Que Foi Identificado ### Endpoints Descobertos (nos logs do console) Baseado nos logs que você forneceu, identificamos: ``` ApiFlightSearch - Busca de voos ApiFlightAvailability - Disponibilidade ApiAccount - Dados da conta ApiAirports - Informações de aeroportos ApiBoardingTax - Taxas de embarque ApiMemberFlight - Voos do membro ApiGraphQL - Endpoint GraphQL ApiOAG - Dados OAG ``` ### Bases de URL Identificadas ``` https://api-air-search-blue.smiles.com.br https://api-airlines-availability.smiles.com.br https://www.smiles.com.br/mfe/ ``` ## 📊 Estratégias de Integração ### 1. Estimativa Local (IMPLEMENTADO ✅) **Vantagens:** - Funciona imediatamente - Sem bloqueios - Rápido **Desvantagens:** - Valores aproximados - Não reflete promoções - Pode estar desatualizado **Como funciona:** ```php // Tabela de estimativas baseada em documentação pública $distances = [ 'GRU-GIG' => ['ECONOMY' => 5000, 'BUSINESS' => 15000], 'GRU-BSB' => ['ECONOMY' => 7500, 'BUSINESS' => 20000], // ... ]; ``` ### 2. Web Scraping com cURL (PARCIAL ⚠️) **Status:** Implementado mas provavelmente bloqueado **Desafios:** - WAF (Web Application Firewall) - Autenticação necessária - JavaScript dinâmico - CAPTCHA **Código atual:** ```php function searchSmilesFlights($origin, $dest, $date, $adults = 1, &$debug = []) { // Tenta acessar endpoints possíveis // Provavelmente retornará erro 403/401 } ``` ### 3. Browser Automation (NÃO IMPLEMENTADO ❌) **Recomendado para valores reais** #### Opção A: Puppeteer (Node.js) ```javascript // smiles_scraper.js const puppeteer = require('puppeteer'); async function scrapeSmilesData(origin, dest, date) { const browser = await puppeteer.launch({ headless: true }); const page = await browser.newPage(); // Navega para o Smiles const url = `https://www.smiles.com.br/mfe/emissao-passagem?...`; await page.goto(url, { waitUntil: 'networkidle2' }); // Aguarda os resultados carregarem await page.waitForSelector('.flight-card', { timeout: 30000 }); // Extrai os dados const flights = await page.evaluate(() => { const cards = document.querySelectorAll('.flight-card'); return Array.from(cards).map(card => ({ miles: card.querySelector('.miles-value')?.textContent, price: card.querySelector('.price-value')?.textContent, // ... })); }); await browser.close(); return flights; } ``` **Como executar do PHP:** ```php function scrapeSmilesWeb($origin, $dest, $date) { $command = sprintf( 'node smiles_scraper.js %s %s %s', escapeshellarg($origin), escapeshellarg($dest), escapeshellarg($date) ); $output = shell_exec($command); return json_decode($output, true); } ``` #### Opção B: Selenium WebDriver (PHP) ```php use Facebook\WebDriver\Remote\RemoteWebDriver; use Facebook\WebDriver\WebDriverBy; function scrapeSmilesSelenium($origin, $dest, $date) { $host = 'http://localhost:4444/wd/hub'; $driver = RemoteWebDriver::create($host, DesiredCapabilities::chrome()); $url = "https://www.smiles.com.br/mfe/emissao-passagem?..."; $driver->get($url); // Aguarda carregar $driver->wait(10)->until( WebDriverExpectedCondition::presenceOfElementLocated( WebDriverBy::className('flight-card') ) ); // Extrai dados $elements = $driver->findElements(WebDriverBy::className('flight-card')); $results = []; foreach ($elements as $el) { $results[] = [ 'miles' => $el->findElement(WebDriverBy::className('miles-value'))->getText(), // ... ]; } $driver->quit(); return $results; } ``` ### 4. Proxy/Interceptação de Rede (AVANÇADO 🔴) **Como funciona:** 1. Abre o Smiles no navegador 2. Usa Proxy (Fiddler, Charles, mitmproxy) 3. Intercepta requisições da API 4. Replica headers e cookies 5. Automatiza as chamadas **Exemplo com mitmproxy:** ```python # smiles_proxy.py from mitmproxy import http def request(flow: http.HTTPFlow) -> None: if "api-air-search" in flow.request.pretty_url: print(f"Request: {flow.request.pretty_url}") print(f"Headers: {flow.request.headers}") print(f"Body: {flow.request.text}") def response(flow: http.HTTPFlow) -> None: if "api-air-search" in flow.request.pretty_url: print(f"Response: {flow.response.text}") ``` Executar: ```bash mitmproxy -s smiles_proxy.py ``` ## 🛠️ Instalação de Ferramentas ### Puppeteer (Node.js) ```bash npm install puppeteer ``` ### Selenium (PHP) ```bash composer require php-webdriver/webdriver ``` Baixar ChromeDriver: ```bash # Windows choco install chromedriver # Linux sudo apt-get install chromium-chromedriver ``` ### Goutte (PHP - Scraping simples) ```bash composer require fabpot/goutte ``` ## 📝 Código de Exemplo Completo com Puppeteer ```javascript // smiles_scraper.js const puppeteer = require('puppeteer'); async function getSmilesMiles(origin, dest, date, adults = 1) { try { const browser = await puppeteer.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'] }); const page = await browser.newPage(); // User agent para não ser detectado await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'); // Monta URL const timestamp = new Date(date).getTime(); const url = `https://www.smiles.com.br/mfe/emissao-passagem?tripType=1&originAirport=${origin}&destinationAirport=${dest}&departureDate=${timestamp}&adults=${adults}&children=0&infants=0&searchType=g3&cabin=ECONOMIC&originAirportIsAny=true&destinationAirportIsAny=true`; console.log(`Navegando para: ${url}`); await page.goto(url, { waitUntil: 'networkidle2', timeout: 60000 }); // Aguarda resultados (ajuste o seletor conforme necessário) console.log('Aguardando resultados...'); await page.waitForSelector('[data-testid="flight-card"], .flight-result, .smiles-card', { timeout: 30000 }); // Extrai dados const flights = await page.evaluate(() => { // AJUSTE OS SELETORES CONFORME A ESTRUTURA REAL DO SITE const cards = document.querySelectorAll('[data-testid="flight-card"], .flight-card'); return Array.from(cards).map(card => { const milesEl = card.querySelector('.miles, [data-testid="miles-value"]'); const priceEl = card.querySelector('.price, [data-testid="price-value"]'); const timeEl = card.querySelector('.time, [data-testid="departure-time"]'); return { miles: milesEl ? milesEl.textContent.trim() : null, price: priceEl ? priceEl.textContent.trim() : null, time: timeEl ? timeEl.textContent.trim() : null, }; }); }); await browser.close(); console.log(JSON.stringify({ success: true, data: flights })); return flights; } catch (error) { console.error(JSON.stringify({ success: false, error: error.message })); process.exit(1); } } // Argumentos da linha de comando const [,, origin, dest, date, adults] = process.argv; getSmilesMiles(origin, dest, date, adults || 1); ``` **Integração com PHP:** ```php function getSmilesRealData($origin, $dest, $date, $adults = 1) { $scriptPath = __DIR__ . '/smiles_scraper.js'; $command = sprintf( 'node %s %s %s %s %d 2>&1', escapeshellarg($scriptPath), escapeshellarg($origin), escapeshellarg($dest), escapeshellarg($date), (int)$adults ); $output = shell_exec($command); $result = json_decode($output, true); if ($result && $result['success']) { return $result['data']; } return null; } ``` ## 🎯 Situação Atual do Sistema ### O Que Funciona ✅ 1. **Estimativa de milhas Smiles** baseada em tabela conhecida 2. **Link direto** para o site do Smiles com parâmetros preenchidos 3. **Comparação visual** entre LATAM Pass e Smiles 4. **Interface completa** com badges e cores ### O Que NÃO Funciona ❌ 1. **API direta** - bloqueada ou requer autenticação 2. **Valores reais em tempo real** - apenas estimativas 3. **Promoções e ofertas** - não são capturadas ### Como Melhorar 1. **Implementar Puppeteer** para obter valores reais 2. **Adicionar cache** para reduzir requisições 3. **Sistema de fila** para processar scraping em background 4. **Notificações** quando houver promoções ## 🔒 Considerações de Segurança ### Rate Limiting Adicione delays entre requisições: ```php function searchSmilesWithRateLimit($origin, $dest, $date) { static $lastRequest = 0; $minInterval = 5; // segundos $elapsed = time() - $lastRequest; if ($elapsed < $minInterval) { sleep($minInterval - $elapsed); } $result = searchSmilesFlights($origin, $dest, $date); $lastRequest = time(); return $result; } ``` ### User Agent Rotation ```php $userAgents = [ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36...', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36...', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36...', ]; $randomUA = $userAgents[array_rand($userAgents)]; ``` ## 📚 Recursos Adicionais ### Documentação - [Puppeteer Docs](https://pptr.dev/) - [Selenium WebDriver](https://www.selenium.dev/documentation/) - [mitmproxy](https://mitmproxy.org/) ### Bibliotecas PHP - [Goutte](https://github.com/FriendsOfPHP/Goutte) - Web Scraping - [php-webdriver](https://github.com/php-webdriver/php-webdriver) - Selenium - [GuzzleHTTP](https://github.com/guzzle/guzzle) - HTTP client avançado ## ⚖️ Conclusão A integração completa com Smiles é **tecnicamente possível**, mas: 1. **Requer ferramentas avançadas** (Puppeteer/Selenium) 2. **Pode violar Termos de Serviço** 3. **Está sujeita a bloqueios** 4. **Valores estimados são suficientes** para comparação básica ### Recomendações - ✅ Use estimativas para comparação geral - ✅ Forneça links diretos ao site oficial - ✅ Seja transparente sobre as limitações - ❌ Não tente burlar sistemas de segurança - ❌ Não use comercialmente sem autorização - ❌ Não sobrecarregue servidores --- **Use com responsabilidade e sempre respeite os Termos de Serviço!**