| 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) |
|
|
| |
| 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." |
| } |
|
|
| |
| 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)} |
|
|