from fastapi import FastAPI, Query, Response import undetected_chromedriver as uc import requests import time import json import os from typing import Optional app = FastAPI() COOKIES_FILE = "cf_cookies.json" def save_cookies(cookies: dict): with open(COOKIES_FILE, "w") as f: json.dump(cookies, f) def load_cookies() -> Optional[dict]: if not os.path.exists(COOKIES_FILE): return None with open(COOKIES_FILE, "r") as f: return json.load(f) def get_cf_cookie(url): print("🔍 Iniciando navegador para resolver challenge de Cloudflare...") try: options = uc.ChromeOptions() options.headless = True options.add_argument("--no-sandbox") options.add_argument("--disable-dev-shm-usage") options.add_argument("--disable-blink-features=AutomationControlled") driver = uc.Chrome(options=options) driver.get(url) # Esperar hasta 30 segundos para que Cloudflare entregue cf_clearance max_wait = 30 cf_clearance = None domain = None for _ in range(max_wait): cookies = driver.get_cookies() for cookie in cookies: if cookie["name"] == "cf_clearance": cf_clearance = cookie["value"] domain = cookie["domain"] break if cf_clearance: break time.sleep(1) driver.quit() if cf_clearance: print("✅ cf_clearance encontrada:", cf_clearance) result = {"cf_clearance": cf_clearance, "domain": domain} save_cookies(result) return result else: print("⚠️ No se encontró cf_clearance") return None except Exception as e: print("❌ Error con el navegador:", str(e)) return None @app.get("/") def root(): return {"message": "FastAPI + Cloudflare Bypass funcionando ✅"} @app.get("/cookie") def get_cookie( url: str = "https://www.visa.com.do/cmsapi/fx/rates?amount=1&fee=3&utcConvertedDate=10%2F19%2F2025&exchangedate=10%2F19%2F2025&fromCurr=DOP&toCurr=USD" ): result = get_cf_cookie(url) if result: return result return {"error": "No se pudo obtener cf_clearance"} @app.get("/scrape") def scrape(url: str = Query(..., description="URL a scrapear")): cookie_result = load_cookies() if not cookie_result: cookie_result = get_cf_cookie(url) if not cookie_result: return { "error": "No se pudo obtener cf_clearance. Puede que el sitio no esté protegido por Cloudflare o hubo un error con el navegador." } 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" } cookies = { "cf_clearance": cookie_result["cf_clearance"] } try: res = requests.get(url, headers=headers, cookies=cookies, timeout=10) if res.status_code in (403, 503): os.remove(COOKIES_FILE) return { "error": f"cf_clearance caducada o inválida (status {res.status_code}). Intenta regenerarla." } # Detectar tipo de contenido y devolver el body completo content_type = res.headers.get("Content-Type", "").lower() if "application/json" in content_type: return Response(content=res.text, media_type="application/json") else: return Response(content=res.text, media_type="text/html") except Exception as e: return {"error": str(e)}