elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.


Tema destacado: Usando Git para manipular el directorio de trabajo, el índice y commits (segunda parte)


+  Foro de elhacker.net
|-+  Programación
| |-+  Python (Moderador: Danielㅤ)
| | |-+  Ayuda con webscraping y cloudflare.............
0 Usuarios y 6 Visitantes están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: Ayuda con webscraping y cloudflare.............  (Leído 54,317 veces)
rasmus

Desconectado Desconectado

Mensajes: 2


Ver Perfil
Ayuda con webscraping y cloudflare.............
« en: 31 Mayo 2025, 14:50 pm »

Ayuda estoy pudiendo hacer descargas pero no logro hacer scroll... me gustaria aprender hacer el scraping evitando el bloqueo de cloudflare.


import os
import re
import requests
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from PIL import Image
from io import BytesIO
import time
import json

def configurar_driver():
    """Configura Chrome para evitar detección"""
    chrome_options = Options()
    chrome_options.add_argument("--no-sandbox")
    chrome_options.add_argument("--disable-dev-shm-usage")
    chrome_options.add_argument("--disable-blink-features=AutomationControlled")
    chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
    chrome_options.add_experimental_option('useAutomationExtension', False)
    chrome_options.add_argument("--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")
   
    driver = webdriver.Chrome(options=chrome_options)
    driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})")
    return driver

def descargar_miniaturas_coleccion(url_coleccion, carpeta_destino="imagenes_hueforge"):
    """
    Descarga específicamente las imágenes de portada/miniatura de la colección
    """
    os.makedirs(carpeta_destino, exist_ok=True)
    driver = configurar_driver()
   
    try:
        print("🔗 Accediendo a la página de colección...")
        driver.get(url_coleccion)
       
        # Esperar a que cargue
        WebDriverWait(driver, 15).until(
            EC.presence_of_element_located((By.TAG_NAME, "body"))
        )
       
        # Scroll para cargar contenido dinámico
        print("📜 Cargando todos los elementos...")
        last_height = driver.execute_script("return document.body.scrollHeight")
       
        while True:
            driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
            time.sleep(2)
            new_height = driver.execute_script("return document.body.scrollHeight")
            if new_height == last_height:
                break
            last_height = new_height
       
        print("🔍 Buscando miniaturas de modelos...")
       
        # Múltiples estrategias para encontrar las tarjetas de modelos
        modelos_encontrados = []
       
        # Estrategia 1: Buscar contenedores de modelos
        selectores_contenedor = [
            "[class*='model-card']",
            "[class*='model-item']",
            "[class*='card']",
            "[data-testid*='model']",
            "article",
            ".grid > div",
            "[class*='collection-item']"
        ]
       
        for selector in selectores_contenedor:
            try:
                elementos = driver.find_elements(By.CSS_SELECTOR, selector)
                print(f"📊 Selector '{selector}': {len(elementos)} elementos")
               
                for elemento in elementos:
                    try:
                        # Buscar imagen dentro del contenedor
                        img = elemento.find_element(By.TAG_NAME, "img")
                        src = img.get_attribute("src")
                       
                        # Buscar título del modelo
                        titulo = None
                        selectores_titulo = ["h1", "h2", "h3", "h4", "[class*='title']", "[class*='name']", "a"]
                       
                        for sel_titulo in selectores_titulo:
                            try:
                                elem_titulo = elemento.find_element(By.CSS_SELECTOR, sel_titulo)
                                titulo = elem_titulo.text.strip()
                                if titulo and len(titulo) > 2:
                                    break
                            except:
                                continue
                       
                        # Si no encuentra título, usar atributo alt de la imagen
                        if not titulo:
                            titulo = img.get_attribute("alt") or "modelo_sin_titulo"
                       
                        if src and titulo:
                            modelos_encontrados.append({
                                'src': src,
                                'titulo': titulo,
                                'elemento_html': elemento.get_attribute('outerHTML')[:200]
                            })
                           
                    except Exception as e:
                        continue
                       
            except Exception as e:
                print(f"❌ Error con selector {selector}: {e}")
                continue
       
        # Eliminar duplicados por URL de imagen
        urls_vistas = set()
        modelos_unicos = []
       
        for modelo in modelos_encontrados:
            if modelo['src'] not in urls_vistas:
                urls_vistas.add(modelo['src'])
                modelos_unicos.append(modelo)
       
        print(f"📊 Miniaturas únicas encontradas: {len(modelos_unicos)}")
       
        if len(modelos_unicos) == 0:
            print("⚠️ No se encontraron miniaturas. Probando método alternativo...")
           
            # Método alternativo: todas las imágenes de la página
            todas_imagenes = driver.find_elements(By.TAG_NAME, "img")
            print(f"🖼️ Total de imágenes en la página: {len(todas_imagenes)}")
           
            for i, img in enumerate(todas_imagenes):
                src = img.get_attribute("src")
                alt = img.get_attribute("alt") or f"imagen_{i}"
               
                # Filtrar imágenes que parezcan miniaturas de modelos
                if src and any(keyword in src.lower() for keyword in ['thumb', 'preview', 'model', 'image']):
                    modelos_unicos.append({
                        'src': src,
                        'titulo': alt,
                        'elemento_html': f"img alt='{alt}'"
                    })
       
        # Guardar información de debug
        with open(os.path.join(carpeta_destino, "debug_modelos.json"), "w", encoding="utf-8") as f:
            json.dump(modelos_unicos, f, indent=2, ensure_ascii=False)
       
        # Descargar las miniaturas
        exitos = 0
        errores = 0
       
        for i, modelo in enumerate(modelos_unicos):
            titulo = modelo['titulo']
            src = modelo['src']
           
            print(f"⬇️ {i+1}/{len(modelos_unicos)}: {titulo[:50]}...")
           
            try:
                # Limpiar nombre del archivo
                titulo_limpio = re.sub(r'[<>:"/\\|?*]', '', titulo).strip()
                titulo_limpio = re.sub(r'\s+', '_', titulo_limpio)[:100]
               
                if descargar_imagen(src, titulo_limpio, carpeta_destino):
                    exitos += 1
                else:
                    errores += 1
                   
            except Exception as e:
                print(f"❌ Error procesando {titulo}: {e}")
                errores += 1
       
        print(f"\n📊 RESUMEN:")
        print(f"✅ Miniaturas descargadas: {exitos}")
        print(f"❌ Errores: {errores}")
        print(f"📁 Carpeta: {os.path.abspath(carpeta_destino)}")
        print(f"🔍 Ver debug_modelos.json para detalles")
       
    finally:
        driver.quit()

def descargar_imagen(url, nombre_archivo, carpeta):
    """Descarga una imagen desde URL"""
    try:
        headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
            "Referer": "https://pagina-.com/"
        }
       
        response = requests.get(url, headers=headers, timeout=30)
        response.raise_for_status()
       
        # Verificar que es una imagen válida
        img = Image.open(BytesIO(response.content))
       
        # Convertir a RGB si es necesario
        if img.mode in ('RGBA', 'LA', 'P'):
            img = img.convert('RGB')
       
        # Guardar como JPG
        ruta_archivo = os.path.join(carpeta, f"{nombre_archivo}.jpg")
        img.save(ruta_archivo, "JPEG", quality=90)
       
        print(f"✅ {nombre_archivo}.jpg ({img.size[0]}x{img.size[1]})")
        return True
       
    except Exception as e:
        print(f"❌ Error descargando {nombre_archivo}: {e}")
        return False

def mostrar_instrucciones_manuales():
    """Muestra instrucciones para identificar las miniaturas correctas"""
    print("""
    🎯 IDENTIFICAR MINIATURAS MANUALMENTE:
   
    1. Abre la colección en tu navegador
    2. Presiona F12 → pestaña Elements
    3. Click en el selector (flecha) y haz click en una miniatura de reloj
    4. Observa el HTML para identificar la estructura
   
    Las miniaturas suelen estar en:
    - <img> dentro de contenedores como .model-card, .grid-item, article
    - URLs que contienen: thumb, preview, model, small
    - Tamaños típicos: 200x200, 300x300, 400x400 píxeles
   
    🔧 Script manual para consola del navegador:
    """)
   
    script_manual = '''
    // Ejecutar en consola (F12 → Console)
   
    // Buscar todas las imágenes que parezcan miniaturas
    let miniaturas = Array.from(document.querySelectorAll('img'))
        .filter(img => {
            let src = img.src;
            let width = img.naturalWidth || img.width;
            let height = img.naturalHeight || img.height;
           
            // Filtrar por tamaño y URL
            return src &&
                   (width >= 150 && width <= 500) &&
                   (height >= 150 && height <= 500) &&
                   (src.includes('thumb') || src.includes('preview') || src.includes('model'));
        });
   
    console.log(`Miniaturas encontradas: ${miniaturas.length}`);
   
    // Mostrar información de cada miniatura
    miniaturas.forEach((img, i) => {
        console.log(`${i+1}. ${img.alt || 'Sin título'}`);
        console.log(`   URL: ${img.src}`);
        console.log(`   Tamaño: ${img.naturalWidth}x${img.naturalHeight}`);
        console.log('---');
    });
   
    // Descargar automáticamente (puede fallar por seguridad del navegador)
    miniaturas.forEach((img, i) => {
        let a = document.createElement('a');
        a.href = img.src;
        a.download = `reloj_${i+1}_${(img.alt || 'modelo').replace(/[^a-zA-Z0-9]/g, '_')}.jpg`;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
    });
    '''
   
    print(script_manual)

if __name__ == "__main__":
    url_coleccion = "https://pagina-.com/collections/1715414-wall-clock-hueforge"
   
    print("🎯 DESCARGADOR DE MINIATURAS DE COLECCIÓN")
    print("=" * 50)
    print("1. Descargar con Selenium (automático)")
    print("2. Mostrar instrucciones manuales")
   
    opcion = input("\nElige opción (1/2): ").strip()
   
    if opcion == "1":
        try:
            descargar_miniaturas_coleccion(url_coleccion)
        except Exception as e:
            print(f"❌ Error: {e}")
            print("\n💡 Si hay problemas, intenta la opción manual (2)")
    elif opcion == "2":
        mostrar_instrucciones_manuales()
    else:
        print("❌ Opción no válida")


« Última modificación: 31 Mayo 2025, 14:53 pm por rasmus » En línea

Bryantcore

Desconectado Desconectado

Mensajes: 36


Home of the Real Crackers


Ver Perfil
Re: Ayuda con webscraping y cloudflare.............
« Respuesta #1 en: 8 Junio 2025, 07:51 am »

Probablemente sea más útil https://github.com/ultrafunkamsterdam/undetected-chromedriver


En línea

---CONSPIR4CY---DrinkOrDie---FAiRLiGHT---HYBRID---International Network of Crackers---Kalisto---PARADOX---Pirates With Attitudes---Razor 1911---Risciso---SKIDROW---United Software Association---
Danielㅤ
Moderador
***
Desconectado Desconectado

Mensajes: 1.973


🔵🔵🔵🔵🔵🔵🔵


Ver Perfil
Re: Ayuda con webscraping y cloudflare.............
« Respuesta #2 en: 16 Agosto 2025, 23:45 pm »

Hola, aquí hay información de como lograr lo que deseas hacer:

https://stackoverflow.com/questions/20986631/how-can-i-scroll-a-web-page-using-selenium-webdriver-in-python

https://www.browserstack.com/guide/selenium-scroll-down-python

https://www.selenium.dev/documentation/webdriver/actions_api/wheel/

https://www.geeksforgeeks.org/software-testing/selenium-scrolling-a-web-page/

https://scrapeops.io/selenium-web-scraping-playbook/python-selenium-scroll-page/



Saludos
En línea

@XSStringManolo
Hacker/Programador
Colaborador
***
Desconectado Desconectado

Mensajes: 2.459


Turn off the red ligth


Ver Perfil WWW
Re: Ayuda con webscraping y cloudflare.............
« Respuesta #3 en: 17 Agosto 2025, 07:30 am »

Difícil ayudarte sin poder probar el código dado que no compartes la url y no descibres el comportamiento.
En línea

Mi perfil de patrocinadores de GitHub está activo! Puedes patrocinarme para apoyar mi trabajo de código abierto 💖

Eleкtro
Ex-Staff
*
Desconectado Desconectado

Mensajes: 10.020



Ver Perfil
Re: Ayuda con webscraping y cloudflare.............
« Respuesta #4 en: 8 Junio 2026, 21:55 pm »

Tal vez llego tarde a responder, sin embargo, al ser un problema tan común con Selenium, nunca es demasiado tarde para ofrecer una respuesta que le pueda servir a más personas:

1. Lo primero de todo es quitar ese user-agent personalizado en el código que has mostrado. Es absolutamente innecesario y no te va a servir para nada, sino al contrario, solo vas a empeorar la evasión y provocar ser identificado como bot (o como algo "no natural"). Cuando lanzas un navegador con WebDriver, dicho navegador ya utiliza por defecto el user-agent nativo correspondiente a la versión exacta de ese navegador que hayas instanciado. Modificarlo es una muy mala idea (para este objetivo en concreto).



2. Desde hace un par de años hasta la actualidad, exploré diversas alternativas, desde el uso de un "undetected-chromedriver" hasta parchear el binario de Chrome para eliminar cierta firma, entre otras opciones que ya no recuerdo, pero ninguna estrategia ni todas ellas juntas me sirvieron para evitar la detección temprana en Cloudflare en la primera navegación al sitio web objetivo. Y, aunque ignoro si hoy existe una solución definitiva, he comprobado por mi mismo que una estrategia simple y efectiva consiste en utilizar el user-agent nativo, configurar correctamente los argumentos de Chrome y evitar el modo headless. Por cierto, como alternativa al modo headless, resulta eficaz desplazar de forma programática la ventana del navegador Chrome instanciado fuera de los límites de la pantalla (offscreen), o simplemente ocultar la ventana principal de Chrome mediante la función ShowWindow de la API de Windows, lo cual tengo más que comprobado que no afecta a la detección de Cloudflare (aparte de que el user-agent seguirá sin tener el flag "HeadlessChrome" añadido).

Entorno a lo que dije sobre "configurar correctamente los argumentos de Chrome", sugiero probar la siguiente configuración para tu driver Chrome. A mi por lo menos me sirve en varios proyectos de automatización (incluyendo en un scraper de páginas de resultados de un motor de búsqueda de torrents) para completar exitosamente los desafíos de Cloudflare:

Código:
chrome_options.add_argument("--allow-insecure-localhost")
chrome_options.add_argument("--disable-background-networking")
chrome_options.add_argument("--disable-backgrounding-occluded-windows")
chrome_options.add_argument("--disable-blink-features=AutomationControlled")
chrome_options.add_argument("--disable-default-apps")
chrome_options.add_argument("--disable-dev-shm-usage")
chrome_options.add_argument("--disable-features=Translate,TranslateUI")
chrome_options.add_argument("--disable-hang-monitor")
chrome_options.add_argument("--disable-notifications")
chrome_options.add_argument("--disable-popup-blocking")
chrome_options.add_argument("--disable-prompt-on-repost")
chrome_options.add_argument("--disable-sync")
chrome_options.add_argument("--ignore-certificate-errors")
chrome_options.add_argument("--ignore-ssl-errors")
chrome_options.add_argument("--lang=en-US")
chrome_options.add_argument("--no-first-run")
chrome_options.add_argument("--no-sandbox")
chrome_options.add_argument("--noerrdialogs")
chrome_options.add_argument("--remote-debugging-port=0")
chrome_options.add_argument("--test-type")

chrome_options.add_experimental_option('useAutomationExtension', False)
chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])

Nota: Creo que debería compilar en Python, pero no lo he probado; El código lo extraje y lo adapté del siguiente post que publiqué en el foro:

 - https://foro.elhacker.net/net_c_vbnet_asp/libreria_de_snippets_para_vbnet_compartan_aqui_sus_snippets-t378770.0.html;msg2286809#msg2286809

Es importante aclarar que las cookies de Cloudflare (cf_clearance) suelen expirar cada 30 minutos, por lo que cada cierto tiempo te aparecerá un nuevo desafío, pero eso no implica necesariamente una detección como bot, sino un proceso de renovación estándar. Y se debería completar con éxito por sí solo sin interacción de ningún tipo. Eso sí, realizar peticiones de forma muy continuada y sin pausas sí disparará inevitablemente los mecanismos de seguridad (código de error HTTP 429, "Too many requests") y serás marcado como bot.



3. Tercer y última sugerencia: No utilices cualquier IA para generar código en lenguajes de programación. La mayoría de modelos son muy ineptos para cualquier tarea programática que requiera cierta complejidad, cuidado y rigor técnico, y sofisticación. La IA no fabrica, no inventa nada, no es creativa, solo simula serlo encadenando fragmentos de códigos, imitando lo que ya forma parte de su entrenamiento. Si solucionan problemas es por probabilidad estadística, no por inteligencia... y a veces la probabilidad es muy baja.

Ese bloque de código de """Configura Chrome para evitar detección""", por ejemplo, es catastrófico ya que para este objetivo provoca el efecto contrario al deseado por el user-agent colocado a dedo. Estoy convencido que si a la IA le explicas los motivos que he expuesto, lo corroborará, pero claro, ya se lo has tenido que explicar, y eso no debería ser necesario; La IA debería haber evitado introducir un user-agent arbitrario por sí misma.

De todas formas, quiero aclarar que mis conocimientos a nivel técnico sobre el funcionamiento interno del motor de un navegador web (y como este se comunica e interactúa con la web) y sobre redes, Cloudflare y programación web en general, son muy básicos y superficiales. Aprendo sobre la marcha cuando necesito resolver un problema puntual. Por lo que tal vez alguna cosa que yo diga pueda no ser exactamente de esa manera, o podría tener una explicación más sencilla y más precisa, pero tampoco creo ir mal encaminado cuando afirmo algo o expongo conjeturas.

Volviendo al tema de la IA, lo ideal es asignarle siempre un rol inicial a la IA (esto es fundamental, siempre, por ejemplo: "Actúa como un desarrollador profesional de Python especializado en la automatización web con Selenium"), y usar una skill para elevar los resultados a un nivel muy superior, pero los fallos y alucinaciones siguen siendo inevitables a largo plazo cuanto más compleja sea la petición y el código necesario para ponerle solución...

En cada pequeño fragmento de código generado por IA pueden aparecer mil fallos de diseño distintos y simultáneos que, al revisarlo con detalle, se hacen evidentes. Desde decisiones innecesarias e incoherentes hasta simplificaciones excesivas que rompen un código en su totalidad.

En fin. Si quieres obtener mejores resultados que la IA que te haya generado ese código te sugiero usar Claude (Opus 4.x) en modo razonamiento HIGH o MAX, pero con suscripción de pago para no gastar todo el limite de uso en la primera consulta. Y, muchísimo mejor que hacer vibe-coding es el desarrollo guiado por especificación (Spec-driven development en inglés).
« Última modificación: 9 Junio 2026, 00:46 am por Eleкtro » En línea



Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

Mensajes similares
Asunto Iniciado por Respuestas Vistas Último mensaje
Cloudflare bypass
Seguridad
Inzect02 1 5,495 Último mensaje 10 Octubre 2018, 22:23 pm
por kcharro
Ayuda con Cloudflare DNS
Desarrollo Web
WIитX 2 4,600 Último mensaje 14 Junio 2014, 18:14 pm
por WIитX
Instalacion de tapatalk con cloudflare ayuda
Desarrollo Web
WIитX 1 3,427 Último mensaje 7 Octubre 2015, 01:04 am
por WIитX
Cloudflare
Desarrollo Web
dimitrix 3 4,678 Último mensaje 7 Enero 2016, 13:36 pm
por dimitrix
dns Cloudflare..
Redes
H20-X 3 5,137 Último mensaje 9 Junio 2018, 20:54 pm
por AXCESS
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines