Volver al blog
Guías
Mihnea-Octavian ManolacheLast updated on Mar 31, 202611 min read

Los 3 mejores clientes HTTP de Python para el scraping web

Los 3 mejores clientes HTTP de Python para el scraping web

En lo que respecta al web scraping, la variedad de clientes HTTP disponibles para Python convierte a este lenguaje en una de las opciones más populares. Pero, ¿qué son exactamente estos clientes HTTP y cómo se pueden utilizar para crear un rastreador web? Pues bien, en el artículo de hoy trataremos precisamente este tema. Al finalizar este artículo, deberías tener una comprensión sólida sobre:

  • Qué es un cliente HTTP en general
  • Cuáles son los mejores clientes HTTP de Python en 2022
  • Por qué Python es una excelente opción para el web scraping
  • Cómo crear realmente un rastreador web utilizando clientes HTTP

¿Qué son los clientes HTTP de Python y cómo se utilizan?

Para comprender mejor cómo se comunica Internet, es necesario familiarizarse con el Protocolo de Transferencia de Hipertexto (HTTP). Sin embargo, nuestro enfoque principal hoy se centra en los clientes HTTP de Python. Por lo tanto, daré por hecho que ya estás familiarizado con HTTP.

En términos generales, un cliente HTTP se refiere a una instancia o un programa que facilita la comunicación con un servidor. Por ejemplo, un navegador web puede considerarse un cliente HTTP. Sin embargo, como programadores, rara vez utilizamos un navegador real al desarrollar una aplicación, salvo cuando trabajamos en un rastreador web o cuando estamos investigando.

Dicho esto, cuando nos referimos a los clientes HTTP de una manera más programática, normalmente nos referimos a un método o a una instancia de una clase utilizada para ejecutar solicitudes HTTP. Dado que Python es sin duda uno de los lenguajes de programación más populares (y también mi favorito), hoy hablaremos de los mejores clientes HTTP de Python y también de cómo implementarlos en un proyecto real.

Comprender el protocolo HTTP

Antes de continuar, aunque recomiendo consultar la documentación de HTTP, permíteme repasar rápidamente algunos de los conceptos básicos de HTTP. En primer lugar, HTTP es quizás uno de los protocolos de Internet más utilizados. Lo usamos todos los días para intercambiar información entre clientes y servidores. 

Para que esto sea posible, HTTP utiliza métodos de solicitud. Estos métodos indican la acción que un cliente desea realizar en un servidor. Por ejemplo, si quieres obtener información de un servidor, utilizarías GET. Si quieres enviar algo al servidor, utilizarías POST. Aquí tienes una lista de los métodos de solicitud HTTP más comunes:

  • GET: recupera datos del servidor
  • HEAD: recuperar solo el encabezado, sin el cuerpo (los datos reales)
  • POST: envía información al servidor
  • PUT: envía información al servidor y sustituye todas las representaciones actuales del recurso
  • PATCH: envía información al servidor y modifica parcialmente el recurso
  • DELETE: eliminar el recurso del servidor

¿Por qué Python para las solicitudes HTTP?

En primer lugar, Python tiene una sintaxis estupenda y una comunidad aún mejor. Por eso, es perfecto para aprender. Yo mismo, cuando empecé a programar, elegí Python. De hecho, los clientes HTTP de Python fueron de las primeras tecnologías con las que me topé. Pero eso es otro tema. 

Mi objetivo con el artículo de hoy es asegurarme de que te quedes no solo con una comprensión teórica básica, sino también con una visión general de la implementación práctica. 

Y Python es ideal para ambas cosas por varias razones. Por mencionar solo algunas:

  • Sintaxis: escribir en Python se parece mucho a escribir en inglés. Por lo tanto, leer un script de Python te ayudará a relacionar los conceptos teóricos con su implementación real. 
  • Soporte: Python cuenta con una comunidad muy amplia. La mayoría de las veces, si te quedas atascado, una simple pregunta en StackOverflow te dará la respuesta a tu problema. 
  • Disponibilidad: la biblioteca de paquetes de Python es una de las más extensas. Por ejemplo, solo en lo que respecta a los clientes HTTP de Python hay más de una docena de paquetes. Pero hoy nos centraremos en los más populares. 

Los 3 (+1) mejores clientes HTTP de Python

A la hora de clasificar los paquetes para elaborar una lista de los 3 mejores clientes HTTP de Python, creo que es tanto una cuestión de funcionalidad como de preferencia personal. Por lo tanto, es correcto decir que lo que sigue representa mis 3 bibliotecas de clientes HTTP favoritas para Python, más que una clasificación general.

1. Requests: simplicidad potente

Requests es probablemente uno de los clientes HTTP preferidos en la comunidad de Python. Yo no soy una excepción. Siempre que pruebo un nuevo rastreador web, utilizo Python con Requests. Es tan fácil como decir .get y tan potente como un navegador web real. 

Entre otras cosas, la biblioteca Requests ofrece:

  • Verificación SSL 
  • Compatibilidad con proxy para HTTPS
  • Persistencia de cookies y sesiones
  • Función «keep alive»
  • Autenticación personalizada

Y estas son solo algunas. Puedes consultar la lista completa de características aquí. Ahora te mostraré cómo trabajar con requests:

import requests
r = requests.get("http://google.com")
print(r.test)

Como puedes ver, con solo 3 líneas de código, la biblioteca requests nos ayuda a recuperar el código HTML de una fila desde un servidor. En el ejemplo anterior, estamos realizando una solicitud GET al servidor y estamos mostrando el resultado. Pero, como he dicho, esta biblioteca es mucho más versátil. Creemos un ejemplo más complejo, que utilice características como proxies y solicitudes POST:

import requests

def get_params(object):
    params = ''
    for key,value in object.items():
        if list(object).index(key) < len(object) - 1:
            params += f"{key}={value}."
        else:
            params += f"{key}={value}"
    return params

API_KEY = '<YOUR_API_KEY>'

TARGET_URL = 'https://httpbin.org/post'

DATA = {"foo":"bar"}

PARAMETERS = {
    "proxy_type":"datacenter",
    "device":"desktop"
}

PROXY = {
    "http": f"http://webscrapingapi.{ get_params(PARAMETERS) }:{ API_KEY }@proxy.webscrapingapi.com:80",
    "https": f"https://webscrapingapi.{ get_params(PARAMETERS) }:{ API_KEY }@proxy.webscrapingapi.com:8000"
}

response = requests.post(
    url=TARGET_URL,
    data=DATA,
    proxies=PROXY,
    verify=False
)

print(response.text)

Veamos qué estamos haciendo aquí:

  • Estamos definiendo la función `get_params`, que toma un objeto y lo devuelve como una cadena de parámetros de URL.
  • Definimos nuestras variables: undefinedundefinedundefinedundefinedundefined
  • Estamos utilizando el método `post` de Requests para enviar una solicitud HTTP POST.
  • Estamos imprimiendo el cuerpo de la respuesta

2. HTTPX: Requests reinventado

HTTPX es relativamente nuevo en el panorama. Sin embargo, en muy poco tiempo se ha convertido en uno de los clientes HTTP para Python más recomendados. Por ejemplo, Flask (uno de los mayores marcos web para Python) recomienda utilizar HTTPX en su documentación oficial. 

Cuando dije que HTTPX es una reinvención de Requests, fue porque ambas bibliotecas son muy similares en cuanto a sintaxis. De hecho, HTTPX busca la compatibilidad total con Requests. Solo hay unas pocas diferencias de diseño menores entre ambas, que se destacan aquí

Así es como se ve una solicitud POST básica en HTTPX:

import httpx

TARGET_URL = 'https://httpbin.org/post'

DATA = {"foo":"bar"}

r = httpx.post(
   url=TARGET_URL,
   data=DATA,
)

print(r.text)

Como puedes ver, lo que cambiamos principalmente es el nombre del paquete, en comparación con el ejemplo de Requests. Y dado que son tan similares, la pregunta sigue siendo: ¿por qué elegir HTTPX en lugar de Requests? Bueno, para empezar, HTTPX es uno de los pocos clientes HTTP de Python que ofrece soporte asíncrono. En resumen, HTTPX es una excelente opción si quieres refactorizar tu código basado en Requests. 

3. urllib3: conexiones seguras para subprocesos

Python tiene un par de «urllibs», lo que suele confundir a los programadores noveles. La principal diferencia entre urllib, urllib2 y urllib3 radica en las características de cada paquete. urllib fue el cliente HTTP original de Python, incluido en la biblioteca estándar de Python 1.2. urllib2 fue la versión mejorada, introducida en Python 1.6 y destinada a sustituir al urllib original.

Sin embargo, en lo que respecta a urllib3, se trata en realidad de un cliente HTTP de Python de terceros. A pesar de su nombre, esta biblioteca no tiene relación alguna con sus dos «predecesoras». Además, en la comunidad de Python se rumorea que no hay intención de incluir urllib3 en la biblioteca estándar. Al menos en un futuro próximo. 

Aunque este paquete no está vinculado oficialmente a la biblioteca estándar de Python, muchos desarrolladores lo utilizan porque ofrece:

  • Seguridad de subprocesos
  • Verificación SSL/TLS del lado del cliente
  • Compatibilidad con proxies para HTTP y SOCKS
  • Cobertura de pruebas completa

Ahora que hemos cubierto la parte teórica, veamos el ejemplo de implementación:

import urllib3,json

TARGET_URL = 'https://httpbin.org/post'

DATA = {"foo":"bar"}

http = urllib3.PoolManager()

encoded_data = json.dumps(DATA)

r = http.request('POST', TARGET_URL, body=encoded_data)

print(r.data.decode('utf-8'))

Analicemos las diferencias identificadas en urllib3, en comparación con Requests:

  • `http`: una instancia del método `PoolManager`, que gestiona los detalles de la seguridad de subprocesos y el agrupamiento de conexiones
  • `encoded_data`: una cadena JSON convertida, que contiene la carga útil que estamos enviando
  • `r`: la solicitud POST real que estamos realizando con la ayuda de urllib3. Aquí estamos utilizando el método `request` de la instancia `PoolManager`.

Y, finalmente, tenemos que decodificar los datos que recibimos en respuesta a nuestra solicitud. Como puedes ver, hay un par de cosas que hacemos de forma diferente a como se hace con Requests.

Mención de honor: http.client - Cliente HTTP tradicional de Python

http.client también forma parte de la biblioteca estándar de Python. Tradicionalmente, los programadores no lo utilizan directamente. Por ejemplo, urllib lo utiliza como dependencia para gestionar las solicitudes HTTP y HTTPS. Lo he incluido en nuestra clasificación porque creo que, como programadores, es bueno conocer la «estructura» de los paquetes que utilizamos.

Así que, aunque quizá no llegues a crear un proyecto real con http.client, aquí tienes un ejemplo de implementación que, estoy seguro, te ayudará a comprender mejor cómo funcionan los clientes HTTP de Python:

import http.client

TARGET_URL = 'www.httpbin.org'

http = http.client.HTTPSConnection(TARGET_URL)
http.request("GET", "/get")

r = http.getresponse()

print(r.read().decode('utf-8'))

La instancia `HTTPSConnection` toma un par de parámetros, que puedes consultar aquí. En nuestro ejemplo, solo definimos el `method` y la `url` (o, más exactamente, el punto final). Además, al igual que urllib3, http.client devuelve una respuesta codificada. Por lo tanto, tenemos que descodificarla antes de imprimirla.

Caso de uso: Creación de un scraper con Requests

Ahora que sabemos cómo usar los clientes HTTP, asignémonos un pequeño proyecto. Te resultará útil no solo para aplicar lo que has aprendido, sino también para añadir valor a tu propio portfolio de programación. 

Dado que los clientes HTTP de Python se utilizan habitualmente para recopilar información de servidores, el uso más común de estas tecnologías es crear un rastreador web. Así que, de aquí en adelante, nos centraremos en cómo crear un rastreador web utilizando clientes HTTP en Python. Como tengo un favorito personal —requests—, lo utilizaré para este proyecto. Sin embargo, puedes utilizarlo como punto de partida e incluso modificarlo para usar algunas de las otras tecnologías que hemos comentado. Sin más preámbulos, empecemos a programar:

1. Configuración del proyecto

Empecemos creando un nuevo directorio en el que guardaremos los archivos de nuestro rastreador web. Ahora abre una nueva ventana de terminal y ejecuta `cd` para acceder a ese directorio. Aquí queremos iniciar un nuevo entorno virtual. Si utilizas un sistema operativo tipo UNIX, puedes usar:

~ » python3 -m venv env && source env/bin/activate              

Ahora solo tienes que crear un nuevo archivo Python que contendrá nuestra lógica y abrirlo en el IDE que prefieras. Si quieres usar la terminal, simplemente pega el siguiente comando:

~ » touch scraper.py && code .                                         

2. Instalación de dependencias

Usaremos pip para instalar los paquetes que necesitamos para este proyecto. Por ahora, hemos decidido que vamos a utilizar Requests, pero no es suficiente para un rastreador web. Un rastreador web también implica el manejo de los datos. Esto significa que necesitamos analizar el HTML recopilado de los servidores. Por suerte, la biblioteca de Python ofrece una gran variedad de paquetes. Sin embargo, para este proyecto utilizaremos BeautifulSoup. Para instalar los paquetes, simplemente pega el siguiente comando:

~ » python3 -m pip install requests bs4                                    

3. Escribir la lógica

Dividiremos nuestro código en dos secciones: una para la extracción de datos y otra para la manipulación de datos. La primera parte la cubre el paquete Requests, mientras que la segunda parte la cubre BeautifulSoup. Sin más preámbulos, pasemos a la programación, comenzando por la parte de extracción:

import requests

def scrape( url = None ):
   # if there is no URL, there is no need to use Python HTTP clients
   # We will print a message and stop execution
   if url == None:
       print('[!] Please add a target!')
       return

   response = requests.get( url ) 
   return response

En esta sección, definimos una función con un único parámetro: la URL de destino. Si no se proporciona la URL, mostraremos un mensaje y detendremos la ejecución. De lo contrario, utilizaremos el método get de Requests para obtener la respuesta. Ahora bien, sabemos que los clientes HTTP de Python admiten más métodos, así que añadamos un parámetro condicional:

import requests

def scrape( method = 'get', url = None, data = None ):
   # if there is no URL, there is no need to use Python HTTP clients
   # We will print a message and stop execution
   if url == None:
       print('[!] Please add a target!')
       return

   if method.lower() == 'get':
       response = requests.get( url )

   elif method.lower() == 'post':
       if data == None:
           print('[!] Please add a payload to your POST request!')
           return
       response = requests.post( url, data )
      
   return response

Como puedes ver, hemos añadido un par de parámetros más a nuestra función. El parámetro `method` especifica qué método debe utilizarse para nuestra solicitud. El parámetro `data` representa la carga útil que enviamos con la solicitud POST. Por defecto, el método es GET, por lo que el parámetro `method` no es obligatorio. 

Reto: Añade más métodos a esta función y amplía las capacidades de nuestro scraper. No solo es divertido, sino que también es una buena forma de aprender. Además, podrás personalizar el código para añadirlo a tu portfolio.

Hasta ahora hemos visto la extracción de datos. Analicemos el HTML y hagamos algo con él:

from bs4 import BeautifulSoup

def extract_elements(data = None, el = None):
   if data == None:
       print('[!] Please add some data!')
       return

   if el == None:
       print('[!] Please specify which elements you are targeting!')
       return

   soup = BeautifulSoup(data.text, 'html.parser')
   elements = soup.find_all(el)

   return elements

Pero un rastreador web debería ser capaz de extraer datos más específicos. Por ejemplo, debería poder localizar y devolver elementos basándose en su selector CSS. Así que añadamos la lógica que se encarga de esta parte:

from bs4 import BeautifulSoup

def extract_elements(data = None, el = None, attr = None, attr_value = None):
   if data == None:
       print('[!] Please add some data!')
       return

   if el == None:
       print('[!] Please specify which elements you are targeting!')
       return

   soup = BeautifulSoup(data.text, 'html.parser')
   elements = soup.find_all(el, { attr : attr_value })

   return elements

BeautifulSoup nos permite extraer datos específicos basándonos en sus atributos. Así que aquí hemos añadido dos nuevos parámetros que nos ayudarán a localizar y extraer elementos basándonos en sus atributos.

Ahora tenemos todo lo que necesitamos. Solo queda combinar las dos secciones y ya tendremos nuestro rastreador web. Una vez que hayas montado tu código, simplemente:

  • Crea una nueva variable que contenga los datos extraídos con Requests 
  • Imprime los elementos devueltos por BeautifulSoup

Aquí están las dos piezas que le faltaban a su código:

data = scrape('GET', 'https://webscrapingapi.com')
print( extract_elements(data, 'ul') )

Estoy seguro de que ya has averiguado para qué sirve todo y que, a estas alturas, no hace falta ninguna explicación. Al igual que con nuestro scraper, te reto a que experimentes con la función `extract_elements` y consigas que haga algo más que simplemente devolver elementos. 

Conclusión

A la hora de aprender un nuevo concepto de programación, creo que lo mejor es probar con las diferentes tecnologías disponibles. Sin embargo, cuando se trata de construir realmente la infraestructura para un proyecto más amplio, es mejor conocer las fortalezas y debilidades de cada tecnología antes de elegir una. 

Espero que este artículo te haya sido de ayuda de cualquier modo y que ahora tengas una comprensión sólida de cómo funcionan los clientes HTTP de Python. También te animo a que experimentes, ya que estoy seguro de que descubrirás el paquete adecuado para ti.

Acerca del autor
Mihnea-Octavian Manolache, Desarrollador Full Stack @ WebScrapingAPI
Mihnea-Octavian ManolacheDesarrollador Full Stack

Mihnea-Octavian Manolache es ingeniero Full Stack y DevOps en WebScrapingAPI, donde se encarga de desarrollar funciones para los productos y de mantener la infraestructura que garantiza el buen funcionamiento de la plataforma.

Empieza a crear

¿Estás listo para ampliar tu recopilación de datos?

Únete a más de 2000 empresas que utilizan WebScrapingAPI para extraer datos de la web a escala empresarial sin ningún gasto de infraestructura.