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
urllib3
biblioteca, 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
# This tutorial is done with urllib3 version 1.25.8
print(urrlib3.__version__)
Alternativamente, se puede utilizar el Solicitudes módulo, que se construye en la parte superior de
urllib3
. 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 :
- Códigos informativos (entre 100 y 199)
- Códigos correctos (entre 200 y 299): 200 es el más común
- Códigos de redireccionamiento (entre 300 y 399)
- Códigos de error del cliente (entre 400 y 499): 404 es el más común
- 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.
Te puede interesar también:
- La UNAM tiene un curso gratuito sobre nutrición: así puedes acceder a él y aprender a controlar tu peso
- Amazon regala cursos de IA: así puedes aprender machine learning sin gastar un centavo
- Cisco ofrece un curso de ciencia de datos gratis, en tu idioma y con la certificación que las empresas buscan
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) # Imprime 200
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.
Te puede interesar también:
- La UNAM tiene un curso gratuito sobre nutrición: así puedes acceder a él y aprender a controlar tu peso
- Amazon regala cursos de IA: así puedes aprender machine learning sin gastar un centavo
- Cisco ofrece un curso de ciencia de datos gratis, en tu idioma y con la certificación que las empresas buscan
La HTTPResponse
instancia, es decir, nuestro response
objeto contiene el cuerpo de la respuesta. Se puede acceder por la data
propiedad que es un bytes
arroyo. Dado que un sitio web puede responder con una codificación para la que no somos adecuados, y dado que queremos convertir el bytes
a str
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, urllib3
nos permite agregar parámetros a las solicitudes GET , a través del fields
argumento. 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 id
de 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 POST
solicitud, el fields
argumento ahora especificará los datos que se enviarán al servidor, no se recuperarán.
Hemos enviado una cadena JSON, que denota un objeto con title
, body
y userId
. 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 id
s 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 title
y body
:
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 urllib3
mó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 certifi
mó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-data
y 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()
# Sending the request.
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.txt
y 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 urllib3
un potente módulo de Python para manejar solicitudes y respuestas HTTP.