Tutorial: Aprende a enviar solicitudes HTTP en Python con urllib3

Los recursos en la Web se encuentran bajo algún tipo de dirección web (incluso si no son accesibles), a menudo denominada URL (Localizador uniforme de recursos) . Estos recursos son, la mayoría de las veces, manipulados por un usuario final (recuperados, actualizados, eliminados, etc.) utilizando el protocolo HTTP a través de los respectivos métodos HTTP .

En esta guía, veremos cómo aprovechar la urllib3biblioteca, que nos permite enviar solicitudes HTTP a través de Python, mediante programación.

Nota: El modulo urllib3 solo se puede utilizar con Python 3.x.

¿Qué es HTTP?

HTTP (Protocolo de transferencia de hipertexto) es un protocolo de transferencia de datos que se utiliza normalmente para transmitir documentos hipermedia, como HTML, pero también se puede utilizar para transferir JSON, XML o formatos similares. Se aplica en la capa de aplicación del modelo OSI , junto con otros protocolos como FTP (Protocolo de transferencia de archivos) y SMTP (Protocolo simple de transferencia de correo) .

HTTP es la columna vertebral de la World Wide Web como la conocemos hoy y su tarea principal es habilitar un canal de comunicación entre los navegadores web y los servidores web, a través de un ciclo de vida de solicitudes HTTP y respuestas HTTP, los componentes de comunicación fundamentales de HTTP.

Se basa en el modelo cliente-servidor en el que un cliente solicita un recurso y el servidor responde con el recurso, o la falta del mismo.

Una solicitud HTTP típica puede verse así:

GET /tag/java/ HTTP/1.1
Host: stackabuse.com
Accept: */*
User-Agent: Mozilla/5.0 (platform; rv:geckoversion) Gecko/geckotrail Firefox/firefoxversion

Si el servidor encuentra el recurso, el encabezado de la respuesta HTTP contendrá datos sobre cómo le fue al ciclo de solicitud / respuesta:

HTTP/1.1 200 OK
Date: Thu, 22 Jul 2021 18:16:38 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
...

Y el cuerpo de la respuesta contendrá el recurso real, que en este caso es una página HTML:

<!DOCTYPE html>
<html lang="en">
   <head>
      <meta name="twitter:title" content="Stack Abuse"/>
      <meta name="twitter:description" content="Learn Python, Java, JavaScript/Node, Machine Learning, and Web Development through articles, code examples, and tutorials for developers of all skill levels."/>
      <meta name="twitter:url" content="https://stackabuse.com"/>
      <meta name="twitter:site" content="@StackAbuse"/>
      <meta name="next-head-count" content="16"/>
   </head>
...

El módulo urllib3

El módulo urllib3 es el último módulo relacionado con HTTP desarrollado para Python y el sucesor de urllib2. Admite cargas de archivos con codificación de varias partes, gzip, agrupación de conexiones y seguridad de subprocesos. Por lo general, viene preinstalado con Python 3.x, pero si ese no es su caso, se puede instalar fácilmente con:

$ pip install urllib3

Puedes comprobar tu versión de urllib3 accediendo a __version__ en el módulo:

import urllib3

<em># This tutorial is done with urllib3 version 1.25.8</em>
print(urrlib3.__version__)

Alternativamente, se puede utilizar el Solicitudes módulo, que se construye en la parte superior deurllib3 . Es más intuitivo y centrado en el ser humano, y permite una gama más amplia de solicitudes HTTP.

Códigos de estado HTTP

Siempre que se envía una solicitud HTTP, la respuesta, además del recurso solicitado (si está disponible y accesible), también contiene un código de estado HTTP, que indica cómo fue la operación. Es primordial que sepa lo que significa el código de estado que obtuvo, o al menos lo que implica en términos generales.

¿Hay algún problema? Si es así, ¿se debe a la solicitud, al servidor oa mí? *

Hay cinco grupos diferentes de códigos de respuesta :

  1. Códigos informativos (entre 100 y 199)
  2. Códigos correctos (entre 200 y 299): 200 es el más común
  3. Códigos de redireccionamiento (entre 300 y 399)
  4. Códigos de error del cliente (entre 400 y 499): 404 es el más común
  5. Códigos de error del servidor (entre 500 y 599): 500 es el más común

Para enviar solicitudes usando urllib3, usamos una instancia de la clase PoolManager, que se encarga de las solicitudes reales por nosotros, cubiertas en breve.

Todas las respuestas a estas solicitudes se empaquetan en una instancia HTTPResponse que, naturalmente, contiene el valor status de esa respuesta:

import urllib3 

http = urllib3.PoolManager()

response = http.request("GET", "https://blog.facialix.com")
print(response.status) <em># Imprime 200</em>

Cómo enviar solicitudes HTTP en Python con urllib3

Finalmente, echemos un vistazo a cómo enviar diferentes tipos de solicitudes a través de urllib3 y cómo interpretar los datos que se devuelven.

Enviar solicitud HTTP GET

Una solicitud HTTP GET se utiliza cuando un cliente solicita recuperar datos de un servidor, sin modificarlos de ninguna manera o forma.

Para enviar una solicitud HTTP GET en Python, usamos el método request() de la instancia PoolManager, pasando el Verbo HTTP apropiado y el recurso para el que estamos enviando una solicitud:

import urllib3

http = urllib3.PoolManager()

response = http.request("GET", "http://jsonplaceholder.typicode.com/posts/")

print(response.data.decode("utf-8"))

Aquí, enviamos una solicitud GET al marcador de posición {JSON} . Es un sitio web que genera datos JSON ficticios, que se envían al cuerpo de la respuesta. Por lo general, el sitio web se utiliza para probar las solicitudes HTTP, resguardando la respuesta.

La HTTPResponseinstancia, es decir, nuestro responseobjeto contiene el cuerpo de la respuesta. Se puede acceder por la datapropiedad que es un bytesarroyo. Dado que un sitio web puede responder con una codificación para la que no somos adecuados, y dado que queremos convertir el bytesstr de todos modos, usamos decode() en el cuerpo y lo codificamos en UTF-8 para asegurarnos de que podemos analizar los datos de manera coherente.

Finalmente, imprimimos el cuerpo de la respuesta:

[
  {
    "userId": 1,
    "id": 1,
    "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
    "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
  },
  {
    "userId": 1,
    "id": 2,
    "title": "qui est esse",
    "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla"
  },
...

Enviar solicitud HTTP GET con parámetros

Rara vez no agregamos ciertos parámetros a las solicitudes. Las variables de ruta y los parámetros de solicitud son muy comunes y permiten estructuras de enlace dinámicas y recursos de organización. Por ejemplo, es posible que deseemos buscar un comentario específico en una publicación determinada a través de una API http://random.com/posts/get?id=1&commentId=1.

Naturalmente, urllib3nos permite agregar parámetros a las solicitudes GET , a través del fieldsargumento. Acepta un diccionario de los nombres de los parámetros y sus valores:

import urllib3 

http = urllib3.PoolManager()

response = http.request("GET",
                        "http://jsonplaceholder.typicode.com/posts/", 
                        fields={"id": "1"})

print(response.data.decode("utf-8"))

Esto devolverá solo un objeto, con un idde 1:

[
	{
  		"userId": 1,
  		"id": 1,
  		"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
  		"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas 				totam\nnostrum rerum est autem sunt rem eveniet architecto"
	}
]

Solicitud HTTP POST

Una solicitud HTTP POST se utiliza para enviar datos del lado del cliente al lado del servidor. Su uso más común es la carga de archivos o el llenado de formularios, pero se puede usar para enviar cualquier dato a un servidor, con una carga útil:

import urllib3

http = urllib3.PoolManager()
response = http.request("POST", "http://jsonplaceholder.typicode.com/posts", fields={"title": "Created Post", "body": "Lorem ipsum", "userId": 5})

print(response.data.decode("utf-8"))

Aunque nos estamos comunicando con la misma dirección web, debido a que estamos enviando una POSTsolicitud, el fieldsargumento ahora especificará los datos que se enviarán al servidor, no se recuperarán.

Hemos enviado una cadena JSON, que denota un objeto con titlebodyuserId. El servicio de marcador de posición {JSON} también elimina la funcionalidad para agregar entidades , por lo que devuelve una respuesta que nos informa si hemos podido «agregarlo» a la base de datos y devuelve el ID de la publicación «creada»:

{
  "id": 101
}

Solicitud HTTP DELETE

Por último, para enviar solicitudes HTTP DELETE , simplemente modificamos el verbo "DELETE"y apuntamos a una publicación específica a través de su id. Eliminemos todas las publicaciones con la ids de 1..5:

import urllib3

http = urllib3.PoolManager()
for i in range(1, 5):
    response = http.request("DELETE", "http://jsonplaceholder.typicode.com/posts", fields={"id": i})
    print(response.data.decode("utf-8"))

Se devuelve un cuerpo vacío, ya que se eliminan los recursos:

{}
{}
{}
{}

Al crear una API REST, probablemente querrá proporcionar algún código de estado y un mensaje para que el usuario sepa que un recurso se ha eliminado correctamente.

Enviar solicitudes HTTP PATCH

Si bien podemos usar solicitudes POST para actualizar recursos, se considera una buena práctica si mantenemos las solicitudes POST solo para crear recursos. En su lugar, podemos disparar una solicitud PATCH para actualizar un recurso existente.

Consigamos la primera publicación y luego la actualizamos con una nueva titlebody:

import urllib3

data = {
    'title': 'Updated title',
    'body': 'Updated body'
}

http = urllib3.PoolManager()

response = http.request("GET", "http://jsonplaceholder.typicode.com/posts/1")
print(response.data.decode('utf-8'))

response = http.request("PATCH", "https://jsonplaceholder.typicode.com/posts/1", fields=data)
print(response.data.decode('utf-8'))

Esto debería resultar en:

{
  "userId": 1,
  "id": 1,
  "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
  "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
}
{
  "userId": 1,
  "id": 1,
  "title": "Updated title",
  "body": "Updated body"
}

Envíe solicitudes HTTPS seguras en Python con urllib3

El urllib3módulo también proporciona verificación SSL del lado del cliente para conexiones HTTP seguras. Podemos lograr esto con la ayuda de otro módulo, llamado certifi, que proporciona el paquete de certificados estándar de Mozilla.

Su instalación es bastante sencilla a través de pip:

$ pip install certifi

Con certifi.where(), hacemos referencia a la Autoridad de certificación (CA) instalada . Esta es una entidad que emite certificados digitales, en los que se puede confiar. Todos estos certificados de confianza están contenidos en el certifimódulo:

import urllib3
import certifi

http = urllib3.PoolManager(ca_certs=certifi.where())
response = http.request("GET", "https://httpbin.org/get")

print(response.status)

Ahora, podemos enviar una solicitud segura al servidor.

Carga de archivos con urllib3

Utilizando urllib3, también podemos subir archivos a un servidor. Para cargar archivos, codificamos los datos como multipart/form-datay pasamos el nombre del archivo y su contenido como una tupla de file_name: file_data.

Para leer el contenido de un archivo, podemos usar el read()método integrado de Python :

import urllib3
import json

with open("file_name.txt") as f:
    file_data = f.read()

<em># Sending the request.</em>
resp = urllib3.request(
    "POST",
    "https://reqbin.com/post-online",
    fields= {
       "file": ("file_name.txt", file_data),
    }
)

print(json.loads(resp.data.decode("utf-8"))["files"])

Para el propósito del ejemplo, creemos un archivo llamado file_name.txty agreguemos algo de contenido:

Some file data
And some more

Ahora, cuando ejecutamos el script, debería imprimirse:

{'file': 'Some file data\nAnd some more'}

Cuando enviamos archivos usando urllib3, la respuesta data contiene un atributo "files" adjunto, al que accedemos a través de resp.data.decode("utf-8")["files"]. Para hacer que la salida sea un poco más legible, usamos el modulo json para cargar la respuesta y mostrarla como una cadena.

También puede proporcionar un tercer argumento a la tupla, que especifica el tipo MIME del archivo cargado:

... previous code
fields={
  "file": ("file_name.txt", file_data, "text/plain"),
}

Conclusión

En esta guía, hemos analizado cómo enviar solicitudes HTTP utilizando urllib3un potente módulo de Python para manejar solicitudes y respuestas HTTP.


También te podría gustar...

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.