En este tutorial, aprenderás a utilizar la biblioteca Python cloudscraper para eludir la detección de bots de Cloudflare, gestionar errores comunes y explorar soluciones alternativas de scraping para obtener las protecciones antibots más robustas.
Cómo utilizar cloudscraper en Python
En este tutorial, intentarás extraer datos de un sitio web protegido por Cloudflare con y sin Cloudscraper. Para ello, utilizarás los paquetes Beautiful Soup yRequests. Si no estás familiarizado con estos paquetes, consultaesta guía de Scraping web en Pythonpara obtener más información.
Para empezar, instala los paquetes necesarios ejecutando el siguiente comando pip:
pip install tqdm==4.66.5 requests==2.32.3 beautifulsoup4==4.12.3
Para que este tutorial sea más fácil de seguir, se ha creado el siguiente Scraper web para extraer metadatos de artículos de noticias publicados en un día concreto en elsitio web ChannelsTV:
import requests
from bs4 import BeautifulSoup
from datetime import datetime
from tqdm.auto import tqdm
def extract_article_data(article_source, headers):
response = requests.get(article_source, headers=headers)
if response.status_code != 200:
return None
soup = BeautifulSoup(response.content, 'html.parser')
title = soup.find(class_="post-title display-3").text.strip()
date = soup.find(class_="post-meta_time").text.strip()
date_object = datetime.strptime(date, 'Updated %B %d, %Y').date()
categories = [category.text.strip() for category in soup.find('nav', {"aria-label": "breadcrumb"}).find_all('li')]
tags = [tag.text.strip() for tag in soup.find("div", class_="tags").find_all("a")]
article_data = {
'date': date_object,
'title': title,
'link': article_source,
'tags': tags,
'categories': categories
}
return article_data
def process_page(articles, headers):
page_data = []
for article in tqdm(articles):
url = article.find('a', href=True).get('href')
if "https://" not in url:
continue
article_data = extract_article_data(url, headers)
if article_data:
page_data.append(article_data)
return page_data
def scrape_articles_per_day(base_url, headers):
day_data = []
page = 1
while True:
page_url = f"{base_url}/page/{page}"
response = requests.get(page_url, headers=headers)
if not response or response.status_code != 200:
break
soup = BeautifulSoup(response.content, 'html.parser')
articles = soup.find_all('article')
if not articles:
break
page_data = process_page(articles, headers)
day_data.extend(page_data)
page += 1
return day_data
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36',
}
URL = "https://www.channelstv.com/2024/08/01/"
scraped_articles = scrape_articles_per_day(URL, headers)
print(f"{len(scraped_articles)} artículos fueron extraídos.")
print("Muestras:")
print(scraped_articles[:2])
En este código, se definen tres funciones para facilitar el proceso de scraping. La primera, llamada extract_article_data, carga los datos de un artículo individual y extrae metadatos, como su fecha de publicación, título, etiquetas y categorías, a un diccionario de Python, que luego se devuelve. Los pasos de carga y extracción se implementan utilizando las bibliotecas de Python Requests y Beautiful Soup.
La segunda función, process_page, obtiene el enlace a todos los artículos de una página concreta y llama a la función extract_article_data para extraer los datos que contienen y almacena cada diccionario de metadatos en una lista, que luego se devuelve. La última función, llamada scrape_articles_per_day, utiliza un bucle while para incrementar el número de página y extrae los datos de los artículos de cada página hasta llegar a una página que no existe.
A continuación, se define la URL que se va a extraer y se especifica la fecha que se va a filtrar como el 1 de agosto de 2024, así como una variable de encabezados que contiene un agente de usuario de muestra. Se llama a la función scrape_articles_per_day y se pasan las variables URL y encabezados. A continuación, se imprime el número de artículos extraídos y los dos primeros resultados.
Lo ideal sería que este Scraper funcionara, pero no es así porque el sitio web ChannelsTV utiliza Cloudflare para impedir el acceso al contenido de sus páginas web a través de las solicitudes directas implementadas en las funcionesextract_article_datayscrape_articles_per_day.
Cuando intentas ejecutar este script, el resultado es el siguiente:
Se extrajeron 0 artículos.
Muestras:
[]
Incorporar cloudscraper
Anteriormente, cuando intentabas extraer metadatos específicos de un artículo, no se devolvía nada, gracias a la protección de Cloudflare. En esta sección, instalarás y utilizarás cloudscraper para evitar este problema.
Para empezar, instala la biblioteca cloudscraper ejecutando el siguiente comando pip:
pip install cloudscraper==1.2.71
A continuación, importe el paquete y defina una función fetch_html_content como esta:
import cloudscraper
def fetch_html_content(url, headers):
try:
scraper = cloudscraper.create_scraper()
response = scraper.get(url, headers=headers)
if response.status_code == 200:
return response
else:
print(f"Failed to fetch URL: {url}. Status code: {response.status_code}")
return None
except Exception as e:
print(f"An error occurred while fetching URL: {url}. Error: {str(e)}")
return None
Esta función toma la URL que se va a extraer y los encabezados de la solicitud como parámetros de entrada, y devuelve un objeto de respuesta o None. Dentro de la función, se define un bloque try-except. En el bloque try, se crea un Scraper utilizando el método cloudscraper.create_scraper. A continuación, se llama al método scraper.get y se pasan las variables url y headers. Si el código de estado de la respuesta es 200, se devuelve la respuesta. De lo contrario, se imprime un mensaje de error y se devuelve None. Del mismo modo, si se produce un error en el bloque try, se activa el bloque except, en el que se imprime un mensaje apropiado y se devuelve None.
A continuación, sustituye todas las llamadas a requests.get en tu script por esta función fetch_html_content. Inicialmente, realiza esta sustitución en tu función extract_article_data de la siguiente manera:
def extract_article_data(article_source, headers):
response = fetch_html_content(article_source, headers)
A continuación, sustituye la llamada requests.get en tu función scrape_articles_per_day de la siguiente manera:
def scrape_articles_per_day(base_url, headers):
day_data = []
page = 1
while True:
page_url = f"{base_url}/page/{page}"
response = fetch_html_content(page_url, headers)
Al definir esta función, la biblioteca cloudscraper puede ayudarte a eludir las restricciones de Cloudflare.
Cuando ejecutas el código, el resultado es el siguiente:
No se pudo obtener la URL: https://www.channelstv.com/2024/08/01//page/5. Código de estado: 404.
Se recopilaron 55 artículos.
Ejemplos:
[{'date': datetime.date(2024, 8, 1),
'title': 'Resiliencia, gases lacrimógenos, saqueos y toque de queda mientras continúan las protestas #EndBadGovernance',
'link': 'https://www.channelstv.com/2024/08/01/tear-gas-resilience-looting-curfew-as-endbadgovernance-protests-hold/',
'tags': ['Eagle Square', 'Hunger', 'Looting', 'MKO Abiola Park', 'violence'],
'categories': ['Headlines']},
{'date': datetime.date(2024, 8, 1),
'title': 'La madre de un artista ruso liberado en un intercambio de prisioneros espera poder "abrazarla"',
'link': 'https://www.channelstv.com/2024/08/01/mother-of-russian-artist-freed-in-prisoner-swap-waiting-to-hug-her/',
'tags': ['Intercambio de prisioneros', 'Rusia'],
'categories': ['Noticias internacionales']}]
Funciones adicionales de Cloudscraper
Como puede ver, Cloudscraper puede ayudarle a superar la protección IUAM de Cloudflare, pero Cloudscraper también tiene otras características que vale la pena destacar.
Uso de proxies
Los Proxy actúan como servidores intermediarios entre su ordenador y los sitios web de destino, lo que le permite mantener un mayor anonimato mientras navega por Internet. Sus solicitudes se enrutan a través de ellos, de modo que los sitios web de destino, como los protegidos por Cloudflare, ven el Proxy como la fuente del tráfico y no su dispositivo.
Con Cloudscraper, puede definir Proxies y pasarlos a su objeto Cloudscraper ya creado de esta manera:
scraper = cloudscraper.create_scraper()
Proxy = {
'http': 'http://your-proxy-ip:port',
'https': 'https://your-proxy-ip:port'
}
response = scraper.get(URL, proxies=Proxy)
Aquí, defines un objeto Scraper con valores predeterminados. A continuación, defines un diccionario Proxy con proxies http y https. Por último, pasas el objeto del diccionario Proxy al método scraper.get como lo harías con un método request.get normal.
Cambiar el agente de usuario y el intérprete de JavaScript
Aunque en el script anterior se especificó directamente un agente de usuario, la biblioteca cloudscraper también puede generar automáticamente agentes de usuario. Esto reduce las configuraciones manuales necesarias durante la creación de scripts y permite imitar a usuarios reales con diferentes identidades de navegador. Esto se hace de forma aleatoria, pero también puede seleccionar el tipo de agentes de usuario de los que se toma la muestra pasando un parámetro del navegador al método cloudscraper.create_scraper. Este parámetro del navegador contiene un diccionario que almacena valores de cadena para el navegador y la plataforma y valores booleanos para escritorio y móvil.
cloudscraper también le permite especificar el intérprete y el motor de JavaScript que utiliza con su Scraper. El valor predeterminado es un solucionador nativo creado por el equipo de cloudscraper. Otras opciones disponibles son Node.js, Js2Py, ChakraCore y v8eval.
A continuación se muestra un fragmento de código de ejemplo con las especificaciones de un intérprete y un navegador:
Scraper = cloudscraper.create_scraper(
interpreter="nodejs",
browser={
"browser": "chrome",
"platform": "ios",
"desktop": False,
}
)
Aquí, se establece el intérprete como «nodejs» y se pasa un diccionario al parámetro del navegador. Dentro de este diccionario, el navegador se establece en Chrome y la plataforma se establece en «ios». El parámetro de escritorio se establece en False, lo que implica que el navegador se ejecuta en el móvil, ya que los valores de móvil y escritorio se establecen en True de forma predeterminada. En este caso, Cloudflare selecciona los agentes de usuario móviles iOS que se ejecutan en el navegador Chrome.
Gestión de CAPTCHAs
Los CAPTCHAestán diseñados para distinguir entre humanos y bots, y a menudo pueden impedir que se cargue la página web de destino cuando se realiza el scraping. Una de las ventajas de Cloudscraper es que admite algunos solucionadores de CAPTCHA de terceros, dedicados a reCAPTCHA, hCaptcha y otros. Si hay otros solucionadores de CAPTCHA de terceros que le interesen, puede enviar su sugerencia al equipo de Cloudscraper a través de los tickets de soporte de GitHub.
El siguiente fragmento de código muestra cómo modificar tu Scraper para gestionar CAPTCHA:
Scraper = cloudscraper.create_scraper(
captcha={
'provider': 'capsolver',
'api_key': 'your_capsolver_api_key'
}
)
En este código, se especifica Capsolver como proveedor de CAPTCHA y la clave API de Capsolver. Ambos valores se almacenan en un diccionario y se pasan al parámetro CAPTCHA en el método cloudscraper.create_scraper.
Errores comunes de cloudscraper
Aunque cloudscraper es una forma fácil de sortear las restricciones de Cloudflare, es posible que encuentres algunos errores al empezar a utilizarlo. A continuación se indican algunos de los errores más comunes (y sus soluciones) con los que te puedes encontrar.
Módulo no encontrado
El error «módulo no encontrado» es un error común en Python que se produce cuando se intenta importar o utilizar una biblioteca que no existe en el entorno Python.
Cuando se trabaja en Python, se opera dentro de un entorno, y solo las bibliotecas instaladas en ese entorno activo son accesibles por su script o cuaderno. El error «módulo no encontrado» implica que no ha activado el entorno (virtual) relevante o que no ha instalado el paquete en su entorno.
Para activar tu entorno virtual en Windows, ejecuta el siguiente comando:
.<venv-name>Scriptsactivate.bat
Si trabaja con Linux o macOS, puede utilizar el siguiente comando:
source <venv-name>/bin/activate
Si el paquete no está instalado, instálelo ejecutando el siguiente comando:
pip install cloudscraper
cloudscraper no puede eludir la última versión de Cloudflare
El error «cloudscraper no puede omitir la última versión de Cloudflare » se produce cuando intentas utilizar una versión de cloudscraper diseñada para omitir una versión anterior de Cloudflare. Esto supone un problema, ya que las versiones más recientes de Cloudflare pueden incluir cambios que restringen las versiones anteriores de cloudscraper hasta que se actualice la biblioteca Python.
Si está ejecutando una versión anterior de cloudscraper, lo mejor es actualizar su paquete con el siguiente comando:
pip install -U cloudscraper
En los casos en los que ya esté utilizando la versión más reciente de Cloudscraper, es posible que tenga que esperar a una actualización o buscar una solución alternativa que funcione.
Una alternativa a Cloudscraper
Si, después de implementar lo que ha aprendido aquí, sigue teniendo problemas para eludir la protección de Cloudflare, debería considerar el uso de Bright Data.
Bright Data cuenta con una de las redes de proxies más grandes, que incluye proxiesde centros de datos, ISP, móviles y residenciales. Con estos proxies como intermediarios, puede evitar el bloqueo de IP, mejorar el rendimiento, eludir las restricciones geográficas y proteger su privacidad.
Para eludir la protección de Cloudflare utilizando Bright Data, todo lo que tienes que hacer es crear una cuenta, configurarla y obtener tus credenciales API. A continuación, puedes utilizar esas credenciales para acceder a los datos en tu URL de destino de esta manera:
import requests
host = 'brd.superproxy.io'
port = 22225
username = 'brd-customer-<CUSTOMER_ID>-zone-<ZONE_NAME>'
password = '<CONTRASEÑA de zona>'
proxy_url = f'http://{username}:{password}@{host}:{port}'
proxies = {
'http': proxy_url,
'https': proxy_url
}
response = requests.get(URL, proxies=proxies)
Aquí, se realiza una solicitud GET con la biblioteca Python Requests y se pasan los proxies a través del parámetro proxies. Los proxies creados utilizan su nombre de usuario, contraseña, host y número de puerto de Bright Data. Su nombre de usuario, en particular, se define en función de su ID de cliente de Bright Data y el nombre de la zona, todos los cuales se pueden recuperar de su cuenta.
Conclusión
En este tutorial, ha aprendido a utilizar la biblioteca cloudscraper en Python para extraer datos de sitios web protegidos por Cloudflare. También ha aprendido algunos errores comunes que puede encontrar y cómo evitarlos. Aunque cloudscraper puede ser una gran solución para evitar el IUAM de Cloudflare, como cualquier tecnología gratuita, tiene sus límites. Por eso también ha aprendido a utilizar la impresionante red de Proxiesde Bright DatayWeb Unlockerpara acceder a sitios protegidos por Cloudflare.
Bright Data te proporciona herramientas automatizadas que te permiten acceder a datos en Internet sin restricciones. También puedes utilizar su amplia red de Proxies para reducir el número de solicitudes fallidas si la automatización no es tu objetivo.
¿Estás listo para llevar tu scraping web al siguiente nivel? Descubre cómo nuestros proxies premium y nuestros servicios expertos de recopilación de datos web pueden eludir fácilmente incluso las protecciones contra bots más estrictas. ¡Empieza hoy mismo con una prueba gratuita!