El módulo de solicitudes de Python

Tratar con solicitudes HTTP no es una tarea fácil en ningún lenguaje de programación. Si hablamos de Python, viene con dos módulos integrados, urllib y urllib2, para...

Introducción

Tratar con solicitudes HTTP no es una tarea fácil en ningún lenguaje de programación. Si hablamos de Python, viene con dos módulos incorporados, urllib y urllib2, para manejar operaciones relacionadas con HTTP. Ambos módulos vienen con un conjunto diferente de funcionalidades y muchas veces deben usarse juntos. El principal inconveniente de usar urllib es que es confuso (hay pocos métodos disponibles tanto en urllib como en urllib2), la documentación no es clara y necesitamos escribir mucho código para hacer incluso una simple solicitud HTTP .

Para simplificar estas cosas, hay disponible una biblioteca de terceros fácil de usar, conocida como Peticiones, y la mayoría de los desarrolladores prefieren usarla. en su lugar o urllib/urllib2. Es una biblioteca HTTP con licencia Apache2 impulsada por urllib3 y httplib.

Instalación del módulo de solicitudes

Instalar este paquete, como la mayoría de los otros paquetes de Python, es bastante sencillo. Puedes descargar la Solicita el código fuente de Github e instalarla o usar pip:

1
$ pip install requests

Para obtener más información sobre el proceso de instalación, consulte la [documentación oficial] (http://docs.python-requests.org/en/master/user/install/).

Para verificar la instalación, puede intentar importarla como se muestra a continuación:

1
import requests

Si no recibe ningún error al importar el módulo, entonces se realizó correctamente.

Realización de una solicitud GET

GET es, con mucho, el método HTTP más utilizado. Podemos usar la solicitud GET para recuperar datos de cualquier destino. Permítanme comenzar con un ejemplo simple primero. Supongamos que queremos obtener el contenido de la página de inicio de nuestro sitio web e imprimir los datos HTML resultantes. Usando el módulo de Solicitudes, podemos hacerlo como se muestra a continuación:

1
2
3
4
import requests

r = requests.get('https://api.github.com/events')
print(r.content)

Imprimirá la respuesta en forma codificada. Si desea ver el resultado de texto real de la página HTML, puede leer la propiedad .text de este objeto. De manera similar, la propiedad status_code imprime el código de estado actual de la URL:

1
2
3
4
5
import requests

r = requests.get('https://api.github.com/events')
print(r.text)
print(r.status_code)

requests decodificará el contenido sin procesar y le mostrará el resultado. Si desea verificar qué tipo de ‘codificación’ utilizan las ‘solicitudes’, puede imprimir este valor llamando a ‘.encoding’. Incluso el tipo de codificación se puede cambiar cambiando su valor. ¿No es así de simple?

Leer la respuesta

La respuesta de una solicitud HTTP puede contener muchos encabezados que contienen información diferente.

httpbin es un sitio web popular para probar diferentes operaciones HTTP. En este artículo, usaremos httpbin/obtener para analizar la respuesta a una solicitud GET. En primer lugar, debemos averiguar el encabezado de respuesta y cómo se ve. Puede usar cualquier navegador web moderno para encontrarlo, pero para este ejemplo, usaremos el navegador Chrome de Google.

  • En Chrome, abre la URL http://httpbin.org/get, haz clic derecho en cualquier lugar de la página y selecciona la opción "Inspeccionar".
  • Esto abrirá una nueva ventana dentro de su navegador. Actualice la página y haga clic en la pestaña "Red".
  • Esta pestaña "Red" le mostrará todos los diferentes tipos de solicitudes de red realizadas por el navegador. Haga clic en la solicitud "obtener" en la columna "Nombre" y seleccione la pestaña "Encabezados" a la derecha.

Herramientas para desarrolladores de Chrome con httpbin{.img-responsive}

El contenido de los "Encabezados de respuesta" es nuestro elemento obligatorio. Puede ver los pares clave-valor que contienen información diversa sobre el recurso y la solicitud. Intentemos analizar estos valores usando la biblioteca requests:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import requests

r = requests.get('http://httpbin.org/get')
print(r.headers['Access-Control-Allow-Credentials'])
print(r.headers['Access-Control-Allow-Origin'])
print(r.headers['CONNECTION'])
print(r.headers['content-length'])
print(r.headers['Content-Type'])
print(r.headers['Date'])
print(r.headers['server'])
print(r.headers['via'])

Recuperamos la información del encabezado usando r.headers y podemos acceder a cada valor del encabezado usando claves específicas. Tenga en cuenta que la clave no distingue entre mayúsculas y minúsculas.

Del mismo modo, intentemos acceder al valor de respuesta. El encabezado anterior muestra que la respuesta está en formato JSON: (Content-type: application/json). La biblioteca de solicitudes viene con un analizador JSON incorporado y podemos usar requests.get('url').json() para analizarlo como un objeto JSON. Luego, el valor de cada clave de los resultados de la respuesta se puede analizar fácilmente como se muestra a continuación:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import requests

r = requests.get('http://httpbin.org/get')

response = r.json()
print(r.json())
print(response['args'])
print(response['headers'])
print(response['headers']['Accept'])
print(response['headers']['Accept-Encoding'])
print(response['headers']['Connection'])
print(response['headers']['Host'])
print(response['headers']['User-Agent'])
print(response['origin'])
print(response['url'])

El código anterior imprimirá el siguiente resultado:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{'headers': {'Host': 'httpbin.org', 'Accept-Encoding': 'gzip, deflate', 'Connection': 'close', 'Accept': '*/*', 'User-Agent': 'python-requests/2.9.1'}, 'url': 'http://httpbin.org/get', 'args': {}, 'origin': '103.9.74.222'}
{}
{'Host': 'httpbin.org', 'Accept-Encoding': 'gzip, deflate', 'Connection': 'close', 'Accept': '*/*', 'User-Agent': 'python-requests/2.9.1'}
*/*
gzip, deflate
close
httpbin.org
python-requests/2.9.1
103.9.74.222
http://httpbin.org/get

La tercera línea, es decir, r.json(), imprimió el valor JSON de la respuesta. Hemos almacenado el valor JSON en la variable respuesta y luego imprimimos el valor para cada clave. Tenga en cuenta que, a diferencia del ejemplo anterior, el valor-clave distingue entre mayúsculas y minúsculas.

Al igual que JSON y el contenido de texto, podemos usar requests para leer el contenido de la respuesta en bytes para solicitudes que no son de texto usando la propiedad .content. Esto descodificará automáticamente los archivos codificados gzip y deflate.

Paso de parámetros en GET

En algunos casos, deberá pasar parámetros junto con sus solicitudes GET, que toman la forma de cadenas de consulta. Para hacer esto, necesitamos pasar estos valores en el parámetro params, como se muestra a continuación:

1
2
3
4
5
6
7
import requests

payload = {'user_name': 'admin', 'password': 'password'}
r = requests.get('http://httpbin.org/get', params=payload)

print(r.url)
print(r.text)

Aquí, estamos asignando los valores de nuestros parámetros a la variable payload y luego a la solicitud GET a través de params. El código anterior devolverá el siguiente resultado:

1
2
http://httpbin.org/get?password=password&user_name=admin
{"args":{"password":"password","user_name":"admin"},"headers":{"Accept":"*/*","Accept-Encoding":"gzip, deflate","Connection":"close","Host":"httpbin.org","User-Agent":"python-requests/2.9.1"},"origin":"103.9.74.222","url":"http://httpbin.org/get?password=password&user_name=admin"}

Como puede ver, la biblioteca Reqeusts convirtió automáticamente nuestro diccionario de parámetros en una cadena de consulta y la adjuntó a la URL.

Tenga en cuenta que debe tener cuidado con el tipo de datos que pasa a través de las solicitudes GET, ya que la carga útil es visible en la URL, como puede ver en el resultado anterior.

Realización de solicitudes POST

Las solicitudes HTTP POST son opuestas a las solicitudes GET, ya que están destinadas a enviar datos a un servidor en lugar de recuperarlos. Aunque, las solicitudes POST también pueden recibir datos dentro de la respuesta, al igual que las solicitudes GET.

En lugar de usar el método get(), necesitamos usar el método post(). Para pasar un argumento, podemos pasarlo dentro del parámetro data:

1
2
3
4
5
6
import requests

payload = {'user_name': 'admin', 'password': 'password'}
r = requests.post("http://httpbin.org/post", data=payload)
print(r.url)
print(r.text)

Producción:

1
2
http://httpbin.org/post
{"args":{},"data":"","files":{},"form":{"password":"password","user_name":"admin"},"headers":{"Accept":"*/*","Accept-Encoding":"gzip, deflate","Connection":"close","Content-Length":"33","Content-Type":"application/x-www-form-urlencoded","Host":"httpbin.org","User-Agent":"python-requests/2.9.1"},"json":null,"origin":"103.9.74.222","url":"http://httpbin.org/post"}

Los datos estarán "codificados en forma" de forma predeterminada. También puede pasar solicitudes de encabezado más complicadas como una tupla si varios valores tienen la misma clave, una cadena en lugar de un diccionario o un archivo codificado de varias partes.

Envío de archivos con POST

A veces necesitamos enviar uno o más archivos simultáneamente al servidor. Por ejemplo, si un usuario está enviando un formulario y el formulario incluye diferentes campos de formulario para cargar archivos, como la imagen de perfil del usuario, el currículum del usuario, etc. Las solicitudes pueden manejar varios archivos en una sola solicitud. Esto se puede lograr colocando los archivos en una lista de tuplas, como a continuación:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import requests

url = 'http://httpbin.org/post'
file_list = [
    ('image', ('image1.jpg', open('image1.jpg', 'rb'), 'image/png')),
    ('image', ('image2.jpg', open('image2.jpg', 'rb'), 'image/png'))
]

r = requests.post(url, files=file_list)
print(r.text)

Las tuplas que contienen la información de los archivos tienen el formato (field_name, file_info).

Otros tipos de solicitudes HTTP

De manera similar a GET y POST, podemos realizar otras solicitudes HTTP como PUT, DELETE, HEAD y OPTIONS usando la biblioteca requests, como se muestra a continuación:

1
2
3
4
5
6
import requests

requests.put('url', data={'key': 'value'})
requests.delete('url')
requests.head('url')
requests.options('url')

Manejo de redirecciones

La redirección en HTTP significa reenviar la solicitud de red a una URL diferente. Por ejemplo, si hacemos una solicitud a "http://www.github.com", se redirigirá a "https://github.com" mediante una [redirección 301](https ://en.wikipedia.org/wiki/HTTP_301).

1
2
3
4
5
6
import requests

r = requests.post("http://www.github.com")
print(r.url)
print(r.history)
print(r.status_code)

Producción:

1
2
3
https://github.com/
[<Response [301]>, <Response [301]>]
200

Como puede ver, el proceso de redirección se maneja automáticamente mediante “solicitudes”, por lo que no es necesario que lo haga usted mismo. La propiedad history contiene la lista de todos los objetos de respuesta creados para completar la redirección. En nuestro ejemplo, se crearon dos objetos Response con el código de respuesta 301. Las respuestas HTTP 301 y 302 se utilizan para la redirección permanente y temporal, respectivamente.

Si no desea que la biblioteca de solicitudes siga automáticamente los redireccionamientos, puede deshabilitarla pasando el parámetro allow_redirects=False junto con la solicitud.

Manejo de tiempos de espera

Otra configuración importante es decirle a nuestra biblioteca cómo manejar los tiempos de espera o las solicitudes que tardan demasiado en devolverse. Podemos configurar requests para dejar de esperar solicitudes de red usando el parámetro timeout. De forma predeterminada, las solicitudes no tendrán tiempo de espera. Entonces, si no configuramos esta propiedad, nuestro programa puede bloquearse indefinidamente, lo cual no es la funcionalidad que desearía en un proceso que hace esperar a un usuario.

1
2
3
import requests

requests.get('http://www.google.com', timeout=1)

Aquí, se lanzará una excepción si el servidor no responde dentro de 1 segundo (que sigue siendo agresivo para una aplicación del mundo real). Para que esto falle con más frecuencia (a modo de ejemplo), debe establecer el límite de tiempo de espera en un valor mucho más pequeño, como 0.001.

El tiempo de espera se puede configurar para las operaciones "conectar" y "leer" de la solicitud mediante una tupla, lo que le permite especificar ambos valores por separado:

1
2
3
import requests

requests.get('http://www.google.com', timeout=(5, 14))

Aquí, el tiempo de espera de "conectar" es de 5 segundos y el tiempo de espera de "leer" es de 14 segundos. Esto permitirá que su solicitud falle mucho más rápidamente si no puede conectarse al recurso y, si se conecta, le dará más tiempo para descargar los datos.

Cookies y encabezados personalizados

Anteriormente hemos visto cómo acceder a los encabezados usando la propiedad headers. Del mismo modo, podemos acceder a las cookies de una respuesta utilizando la propiedad cookies.

Por ejemplo, el siguiente ejemplo muestra cómo acceder a una cookie con el nombre cookie_name:

1
2
3
4
import requests

r = requests.get('http://www.examplesite.com')
r.cookies['cookie_name']

También podemos enviar cookies personalizadas al servidor proporcionando un diccionario al parámetro cookies en nuestra solicitud GET.

1
2
3
4
import requests

custom_cookie = {'cookie_name': 'cookie_value'}
r = requests.get('http://www.examplesite.com/cookies', cookies=custom_cookie)

Las cookies también se pueden pasar en un objeto Tarro de las galletas. Esto le permite proporcionar cookies para una ruta diferente.

1
2
3
4
5
6
7
8
import requests

jar = requests.cookies.RequestsCookieJar()
jar.set('cookie_one', 'one', domain='httpbin.org', path='/cookies')
jar.set('cookie_two', 'two', domain='httpbin.org', path='/other')

r = requests.get('https://httpbin.org/cookies', cookies=jar)
print(r.text)

Producción:

1
{"cookies":{"cookie_one":"one"}}

De manera similar, podemos crear encabezados personalizados asignando un diccionario al encabezado de la solicitud usando el parámetro headers.

1
2
3
4
5
import requests

custom_header = {'user-agent': 'customUserAgent'}

r = requests.get('https://samplesite.org', headers=custom_header)

El objeto de sesión

El objeto de sesión se usa principalmente para persistir ciertos parámetros, como cookies, a través de diferentes solicitudes HTTP. Un objeto de sesión puede usar una sola conexión TCP para manejar múltiples solicitudes y respuestas de red, lo que resulta en una mejora del rendimiento.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import requests

first_session = requests.Session()
second_session = requests.Session()

first_session.get('http://httpbin.org/cookies/set/cookieone/111')
r = first_session.get('http://httpbin.org/cookies')
print(r.text)

second_session.get('http://httpbin.org/cookies/set/cookietwo/222')
r = second_session.get('http://httpbin.org/cookies')
print(r.text)

r = first_session.get('http://httpbin.org/anything')
print(r.text)

Producción:

1
2
3
4
5
{"cookies":{"cookieone":"111"}}

{"cookies":{"cookietwo":"222"}}

{"args":{},"data":"","files":{},"form":{},"headers":{"Accept":"*/*","Accept-Encoding":"gzip, deflate","Connection":"close","Cookie":"cookieone=111","Host":"httpbin.org","User-Agent":"python-requests/2.9.1"},"json":null,"method":"GET","origin":"103.9.74.222","url":"http://httpbin.org/anything"}

La ruta httpbin /cookies/conjunto/{nombre}/{valor} establecerá una cookie con nombre y valor. Aquí, establecemos diferentes valores de cookies para los objetos first_session y second_session. Puede ver que se devuelve la misma cookie en todas las solicitudes de red futuras para una sesión específica.

De manera similar, podemos usar el objeto de sesión para conservar ciertos parámetros para todas las solicitudes.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import requests

first_session = requests.Session()

first_session.cookies.update({'default_cookie': 'default'})

r = first_session.get('http://httpbin.org/cookies', cookies={'first-cookie': '111'})
print(r.text)

r = first_session.get('http://httpbin.org/cookies')
print(r.text)

Producción:

1
2
3
{"cookies":{"default_cookie":"default","first-cookie":"111"}}

{"cookies":{"default_cookie":"default"}}

Como puede ver, la default_cookie se envía con cada solicitud de la sesión. Si agregamos cualquier parámetro adicional al objeto cookie, se agrega a default_cookie. "first-cookie": "111" se agrega a la cookie predeterminada "default_cookie": "default"

Uso de servidores proxy {#uso de servidores proxy}

El argumento proxies se usa para configurar un servidor proxy para usar en sus solicitudes.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
http = "http://10.10.1.10:1080"
https = "https://10.10.1.11:3128"
ftp = "ftp://10.10.1.10:8080"

proxy_dict = {
  "http": http,
  "https": https,
  "ftp": ftp
}

r = requests.get('http://sampleurl.com', proxies=proxy_dict)

La biblioteca requests también admite proxies MEDIAS. Esta es una característica opcional y requiere que la dependencia requests[socks] esté instalada antes de su uso. Como antes, puedes instalarlo usando pip:

1
$ pip install requests[socks]

Después de la instalación, puede usarlo como se muestra aquí:

1
2
3
4
proxies = {
  'http': 'socks5:user:[correo electrónico protegido]:port'
  'https': 'socks5:user:[correo electrónico protegido]:port'
}

Gestión de SSL

También podemos usar la biblioteca de solicitudes para verificar el certificado HTTPS de un sitio web pasando verify=true con la solicitud.

1
2
3
import requests

r = requests.get('https://www.github.com', verify=True)

Esto arrojará un error si hay algún problema con el SSL del sitio. Si no quiere la verdad, simplemente pase Falso en lugar de Verdadero. Este parámetro se establece en Verdadero de forma predeterminada.

Descarga de un archivo

Para descargar un archivo usando requests, podemos descargarlo transmitiendo el contenido o directamente descargando todo. La bandera stream se usa para indicar ambos comportamientos.

Como probablemente hayas adivinado, si stream es True, entonces requests transmitirá el contenido. Si stream es False, todo el contenido se descargará a la memoria antes de devolvérselo.

Para la transmisión de contenido, podemos iterar el contenido fragmento a fragmento usando el método iter_content o iterar línea por línea usando iter_line. De cualquier manera, descargará el archivo parte por parte.

Por ejemplo:

1
2
3
4
5
6
7
import requests

r = requests.get('https://cdn.pixabay.com/photo/2018/07/05/02/50/sun-hat-3517443_1280.jpg', stream=True)
downloaded_file = open("sun-hat.jpg", "wb")
for chunk in r.iter_content(chunk_size=256):
    if chunk:
        downloaded_file.write(chunk)

El código anterior descargará una imagen del servidor pixabay y la guardará en un archivo local, sun-hat.jpg.

También podemos leer datos sin procesar usando la propiedad raw y stream=True en la solicitud.

1
2
3
4
import requests

r = requests.get("http://exampleurl.com", stream=True)
r.raw

Para descargar o transmitir contenido, iter_content() es la forma preferida.

Errores y excepciones

requests arroja diferentes tipos de excepciones y errores si alguna vez hay un problema de red. Todas las excepciones se heredan de la clase requests.exceptions.RequestException.

Aquí hay una breve descripción de los errores comunes con los que puede encontrarse:

  • Se lanza la excepción ConnectionError en caso de falla de DNS, conexión rechazada o cualquier otro problema relacionado con la conexión.
  • Se genera Timeout si se agota el tiempo de espera de una solicitud.
  • Se genera TooManyRedirects si una solicitud supera el número máximo de redirecciones predefinidas.
  • Se genera la excepción HTTPError para respuestas HTTP no válidas.

Para obtener una lista más completa y una descripción de las excepciones con las que puede encontrarse, consulte la documentación.

Conclusión

En este tutorial te expliqué muchas de las características de la biblioteca requests y las diversas formas de usarla. Puede usar la biblioteca requests no solo para interactuar con una API REST, sino que también se puede usar para extraer datos de un sitio web o para descargar archivos de la web.

Modifique y pruebe los ejemplos anteriores y deje un comentario a continuación si tiene alguna pregunta con respecto a las “solicitudes”. .

Licensed under CC BY-NC-SA 4.0