Quickstart¶
¿Ansioso por empezar? Esta página brinda una buena introducción sobre como empezar a utilizar Requests. Esta guía asume que ya tengas instalado Requests. Si aún no lo has hecho, ve a la sección Instalación.
Primero, asegúrate que:
- Requests esté instalado
- Requests esté actualizado
Empecemos con algunos ejemplos sencillos.
Realizar un petición¶
Realizar una petición en Requests muy sencillo.
Comienza importando el módulo de Requests:
>>> import requests
Ahora, intentemos obtener un página web. Para este ejemplo, vamos a obtener el timeline público de GitHub.:
>>> r = requests.get('https://github.com/timeline.json')
Ahora, tenemos un objeto Response
llamado r
. Podemos
obtener toda la información que necesitamos a partir de este objeto.
En Requests, un API simple significa que todas las formas the peticiones HTTP son obvias. Por ejemplo, así es como realizas una petición HTTP POST:
>>> r = requests.post("http://httpbin.org/post")
¿Qué tal otros tipos de peticiones HTTP?: PUT, DELETE, HEAD y OPTIONS? Todos estos son igual de simples:
>>> r = requests.put("http://httpbin.org/put")
>>> r = requests.delete("http://httpbin.org/delete")
>>> r = requests.head("http://httpbin.org/get")
>>> r = requests.options("http://httpbin.org/get")
Todo esto está bien, pero es solo el comienzo de lo que Requests puede hacer.
Pasar parámetros en URLs¶
Con frecuencia, debes enviar algún tipo de información en el query
string de la URL. Si estuvieses creando la URL a mano, esta información
estaría en forma de pares llave/valor luego del signo de interrogación en
la URL, por ejemplo httpbin.org/get?key=val
. Requests te permite
proveer estos argumentos en forma de diccionario, usando el parámetro en
llave (keyword argument) params
. Como ejemplo, si quisieras pasar
key1=value1
y key2=value2
a httpbin.org/get
, usarías algo
como esto:
>>> payload = {'key1': 'value1', 'key2': 'value2'}
>>> r = requests.get("http://httpbin.org/get", params=payload)
Puedes ver que la URL ha sido codificada correctamente imprimiéndola:
>>> print r.url
u'http://httpbin.org/get?key2=value2&key1=value1'
Nota que cualquier llama del diccionario cuyo valor es None
no será
agregada al query string del URL.
Contenido de respuesta¶
Podemos leer el contenido de la respuesta del servidor. Usemos el timeline de GitHub nuevamente:
>>> import requests
>>> r = requests.get('https://github.com/timeline.json')
>>> r.text
'[{"repository":{"open_issues":0,"url":"https://github.com/...
Requests automáticamente decodificará el contenido que viene del servidor. La mayoría de caracteres unicode serán decodificados correctamente.
Cuando ejecutas una petición, Requests tratará de obtener la codificación
de la respuesta basándose en las cabeceras HTTP. La codificación del
texto que Requests halló (o supuso), será utilizada cuando se acceda a
r.text
. Puedes conocer la codificación que Requests está utilizando,
y cambiarla, usando la propiedad r.encoding
:
>>> r.encoding
'utf-8'
>>> r.encoding = 'ISO-8859-1'
Si cambias la codificación, Requests utilizará este nuevo valor de
r.encoding
siempre que se invoque a r.text
. Podrías querer hacer
esto en cualquier situación donde puedas aplicar una lógica de trabajo
especial para trabajar según la codificación que esté en el contenido.
Por ejemplo, HTTP y XML tienen la habilidad de especificar su
codificación en su cuerpo. En situaciones como esta, deberías usar
r.content
para encontrar la codificación y después configuar
r.encoding
. Esto te permitirá usar r.text
con la codifiación
correcta.
Requests también puede utilizar codificaciones del usuario, en caso de ser necesario.
Si creaste tu propia codificación, y la has registrado usando el módulo codecs
,
puedes asignar el nombre de este codec como valor de r.encoding
y Requests se
encargará de la decodificación.
Contenidos de respuesta binarios¶
También puedes acceder al cuerpo de la respuesta como bytes, para peticiones que no sean de texto:
>>> r.content
b'[{"repository":{"open_issues":0,"url":"https://github.com/...
Las codificaciones de transferencia gzip
y deflate
serán
decodificadas automáticamente.
Por ejemplo, para crear una imagen a partir de datos binarios en una respuesta, puedes usar el siguiente código:
>>> from PIL import Image
>>> from StringIO import StringIO
>>> i = Image.open(StringIO(r.content))
Contenido de respuesta JSON¶
También hay un decodificador de JSON incorporado en Requests, en caso de que estés trabajando con datos JSON:
>>> import requests
>>> r = requests.get('https://github.com/timeline.json')
>>> r.json()
[{u'repository': {u'open_issues': 0, u'url': 'https://github.com/...
Si la decodificación falla, r.json
levantará una excepción. Por
ejemplo, si la respuesta obtiene un código 401 (No Autorizado/
Unauthorized), intentar r.json
mandará una excepción
ValueError: No JSON object could be decoded
.
Contenido de respuesta en crudo¶
En el caso extraño que quieras obtener la respuesta en crudo a nivel
socket, puedes acceder r.raw
. Si quieres hacer esto, asegúrate de
pasar stream=True
en la petición inicial. Una vez que hagas esto,
puedes hacer lo siguiente:
>>> r = requests.get('https://github.com/timeline.json', stream=True)
>>> r.raw
<requests.packages.urllib3.response.HTTPResponse object at 0x101194810>
>>> r.raw.read(10)
'\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03'
De manera general, sin embargo, deberías usar un patrón como este para guardar lo que se recibe del stream a un archivo:
with open(filename, 'wb') as fd:
for chunk in r.iter_content(chunk_size):
fd.write(chunk)
Al usar Response.iter_content
se manejará mucho de lo que deberías
haber manipulado a mano usando Response.raw
directamente. Lo de arriba
es la forma preferida y recomendad de obtener el contenido obtenido
Cabeceras personalizadas¶
Si quieres agregar cabeceras HTTP a una petición, simplemente pasa un dict
al parámetro headers
.
Por ejemplo, en el ejemplo anterior no especificamos la cabecera content-type:
>>> import json
>>> url = 'https://api.github.com/some/endpoint'
>>> payload = {'some': 'data'}
>>> headers = {'content-type': 'application/json'}
>>> r = requests.post(url, data=json.dumps(payload), headers=headers)
Peticiones POST más complicadas¶
Típicamente, quieres enviar información en forma de formulario, como un formulario HTML. Para hacerlo, pasa un diccionario al argumento data. Este diccionario será codificado automáticamente como formulario al momento de realizar la petición:
>>> payload = {'key1': 'value1', 'key2': 'value2'}
>>> r = requests.post("http://httpbin.org/post", data=payload)
>>> print r.text
{
...
"form": {
"key2": "value2",
"key1": "value1"
},
...
}
Existen ocasiones en las que quieres enviar datos en otra codificación. Si pasas un string
en vez de un dict
,
la información será posteada directamente.
Por ejemplo, el API v3 de GitHub acepta información en forma de JSON POST/PATCH:
>>> import json
>>> url = 'https://api.github.com/some/endpoint'
>>> payload = {'some': 'data'}
>>> r = requests.post(url, data=json.dumps(payload))
Pasar un Archivo Multiparte en POST¶
Requests hace que sea simple subir archivos Multiparte:
>>> url = 'http://httpbin.org/post'
>>> files = {'file': open('report.xls', 'rb')}
>>> r = requests.post(url, files=files)
>>> r.text
{
...
"files": {
"file": "<censored...binary...data>"
},
...
}
Puedes establecer explícitamente el nombre del archivo, _content_type_ y encabezados:
>>> url = 'http://httpbin.org/post'
>>> files = {'file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel', {'Expires': '0'})}
>>> r = requests.post(url, files=files)
>>> r.text
{
...
"files": {
"file": "<censored...binary...data>"
},
...
}
Si quieres, puedes enviar cadenas de caracteres para ser recibidas como archivos:
>>> url = 'http://httpbin.org/post'
>>> files = {'file': ('report.csv', 'some,data,to,send\nanother,row,to,send\n')}
>>> r = requests.post(url, files=files)
>>> r.text
{
...
"files": {
"file": "some,data,to,send\\nanother,row,to,send\\n"
},
...
}
Si estás enviando un archivo muy larga como una petición
multipart/form-data
, puedes querer hacer un stream de la petición.
Por defecto, requests
no lo soporta, pero hay un paquete separado
que sí lo hace - requests-toolbelt
–. Deberías leer
la documentación de toolbelt para más
detalles de cómo usarlo.
Códigos de estado de respuesta¶
Podemos verificar el código de estado de la respuesta:
>>> r = requests.get('http://httpbin.org/get')
>>> r.status_code
200
Requests también incluye un objeto para buscar estados de respuesta y pueden ser referenciados fácilmente:
>>> r.status_code == requests.codes.ok
True
Si hacemos una mala petición (respuesta diferente a 200), podemos
levantar una excepción con Response.raise_for_status()
:
>>> bad_r = requests.get('http://httpbin.org/status/404')
>>> bad_r.status_code
404
>>> bad_r.raise_for_status()
Traceback (most recent call last):
File "requests/models.py", line 832, in raise_for_status
raise http_error
requests.exceptions.HTTPError: 404 Client Error
Pero, debido a que nuestro status_code
para r
fue 200
,
cuando llamamos raise_for_status()
obtenemos:
>>> r.raise_for_status()
None
Todo está bien.
Cabeceras de respuesta¶
Podemos ver las cabeceras de respuesta del servidor utilizando un diccionario:
>>> r.headers
{
'status': '200 OK',
'content-encoding': 'gzip',
'transfer-encoding': 'chunked',
'connection': 'close',
'server': 'nginx/1.0.4',
'x-runtime': '148ms',
'etag': '"e1ca502697e5c9317743dc078f67693f"',
'content-type': 'application/json; charset=utf-8'
}
Este diccionario es especial: está hecho únicamente para las cabeceras HTTP. De acuerdo con el RFC 7230 , los nombres de las cabeceras HTTP no hacen distinción entre mayúsculas y minúsculas.
Así que podemos acceder a las cabeceras utilizando letras mayúsculas o minúsculas:
>>> r.headers['Content-Type']
'application/json; charset=utf-8'
>>> r.headers.get('content-type')
'application/json; charset=utf-8'
Cookies¶
Si una respuesta contiene Cookies, puedes acceder a ellas rápidamente:
>>> url = 'http://example.com/some/cookie/setting/url'
>>> r = requests.get(url)
>>> r.cookies['example_cookie_name']
'example_cookie_value'
Para enviar tus propias cookies al servidor, puedes utilizar el
parámetro cookies
:
>>> url = 'http://httpbin.org/cookies'
>>> cookies = dict(cookies_are='working')
>>> r = requests.get(url, cookies=cookies)
>>> r.text
'{"cookies": {"cookies_are": "working"}}'
Historial y Redireccionamiento¶
Requests realizará redireccionamiento para peticiones par todos los verbos, excepto HEAD.
GitHub redirecciona todas las peticiones HTTP hacia HTTPS. Podemos usar
el método history
del objeto Response
para rastrear las
redirecciones. Veamos que hace GitHub:
>>> r = requests.get('http://github.com')
>>> r.url
'https://github.com/'
>>> r.status_code
200
>>> r.history
[<Response [301]>]
La lista Response.history
contiene una lista de
objetos tipo Request
que fueron creados con el fín
de completar la petición. La lista está ordenada desde la petición
más antigüa, hasta las más reciente.
Si estás utilizando GET u OPTIONS, puedes deshabilitar el redireccionamiento
usando el parámetro allow_redirects
:
>>> r = requests.get('http://github.com', allow_redirects=False)
>>> r.status_code
301
>>> r.history
[]
Si estás utilizando HEAD, puedes habilitar el redireccionamento de la misma manera:
>>> r = requests.head('http://github.com', allow_redirects=True)
>>> r.url
'https://github.com/'
>>> r.history
[<Response [301]>]
Timeouts¶
Con el parámetro timeout
puedes indicarle a Requests que deje de
esperar por una respuesta luego de un número determinado de segundos:
>>> requests.get('http://github.com', timeout=0.001)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
requests.exceptions.Timeout: HTTPConnectionPool(host='github.com', port=80): Request timed out. (timeout=0.001)
Note:
timeout
no es el tiempo límite que la respuesta completa se
descargue; de lo contrario, una excepción se levanta si el servidor
no ha dado una respuesta dentro de los seguntos establecidos por
timeout
(más precisamente, si no se han recibido bytes en el
socket por timeout
segundos)
Errores y excepciones:¶
En el caso de un problema de red (falla de DNS, conexión rechazada, etc),
Requests levantará una excepción tipo ConnectionError
.
En el caso de una respuesta HTTP inválida, Requests levantará una excepción tipo :class::HTTPError.
Si se cumple el tiempo de espera (timeout), se levantará una
excepción tipo Timeout
.
Si una petición excede el número configurado de redirecciones
máximas, se levantará una excepción tipo TooManyRedirects
.
Todas las excepciones levantadas por Requests, heredan de
la clase requests.exceptions.RequestException
.
¿Listo para más? Mira la sección avanzado.