Python requests: params, headers y POST con JSON
Ya sabes hacer un GET. Ahora aprenderás a enviar información al servidor: parámetros en la URL, cabeceras y cuerpos JSON o de formulario.
Parte 1: Python requests: Instalación y tu primer GET
Qué vas a aprender en esta parte
Casi toda API real te pide tres cosas: que le digas qué quieres (parámetros en la URL), quién eres o cómo quieres la respuesta (cabeceras) y, cuando creas o modificas datos, qué información envías (el cuerpo de la petición). Requests tiene un argumento para cada una: params, headers, y json o data. Entender cuándo usar cada uno evita la mayoría de los errores 400 y 415 que verás al empezar.
Paso 3: Parámetros de URL y cabeceras
Pasa los parámetros de consulta con params como diccionario y requests se encarga de codificarlos; no concatenes strings a mano.
import requests
parametros = {"buscar": "python requests", "pagina": 2}
r = requests.get("https://httpbin.org/get", params=parametros, timeout=10)
print(r.url)
# https://httpbin.org/get?buscar=python+requests&pagina=2
print(r.json()["args"])
# {'buscar': 'python requests', 'pagina': '2'}
Si un valor es una lista, requests repite el parámetro: {"tag": ["a", "b"]} produce ?tag=a&tag=b.
Las cabeceras se envían con headers. La más habitual es User-Agent, que muchos sitios exigen para identificar tu programa:
cabeceras = {
"User-Agent": "agusbot-tutorial/1.0 (+https://agusbot.com)",
"Accept": "application/json",
}
r = requests.get("https://httpbin.org/headers", headers=cabeceras, timeout=10)
print(r.json()["headers"]["User-Agent"])
Paso 4: POST con JSON y formularios, y los demás métodos
Para enviar JSON usa el argumento json=: requests lo serializa y añade Content-Type: application/json por ti. Para formularios HTML clásicos usa data=.
import requests
# Enviar JSON
nuevo = {"titulo": "Mi primer post", "autor": "agusbot"}
r = requests.post("https://httpbin.org/post", json=nuevo, timeout=10)
print(r.status_code) # 200
print(r.json()["json"]) # {'titulo': 'Mi primer post', 'autor': 'agusbot'}
# Enviar un formulario (application/x-www-form-urlencoded)
r = requests.post("https://httpbin.org/post", data={"usuario": "agus"}, timeout=10)
print(r.json()["form"]) # {'usuario': 'agus'}
El error más común es usar data= con un diccionario cuando la API espera JSON: el servidor recibe un formulario y suele responder 400 o 415.
El resto de métodos HTTP funcionan igual, cambiando el nombre de la función:
| Método | Función | Para qué sirve |
|---|---|---|
| GET | requests.get() | Leer datos |
| POST | requests.post() | Crear un recurso |
| PUT | requests.put() | Reemplazar un recurso completo |
| PATCH | requests.patch() | Modificar solo algunos campos |
| DELETE | requests.delete() | Borrar un recurso |
r = requests.put("https://httpbin.org/put", json={"estado": "publicado"}, timeout=10)
r = requests.patch("https://httpbin.org/patch", json={"estado": "borrador"}, timeout=10)
r = requests.delete("https://httpbin.org/delete", timeout=10)
Cómo depurar lo que realmente envías
Cuando una API rechaza tu petición, lo primero es ver exactamente qué salió de tu programa. Toda respuesta guarda la petición que la originó en respuesta.request, y ahí puedes inspeccionar la URL final, las cabeceras y el cuerpo:
import requests
r = requests.post("https://httpbin.org/post", json={"titulo": "Hola"}, timeout=10)
print(r.request.method) # POST
print(r.request.url) # https://httpbin.org/post
print(r.request.headers["Content-Type"]) # application/json
print(r.request.body) # b'{"titulo": "Hola"}'
Compara esa salida con la documentación de la API. Casi siempre el problema es un Content-Type incorrecto, un campo mal escrito o un parámetro que esperabas ver en la URL y no está.
Errores frecuentes con parámetros y cuerpos
- Usar
data=en lugar dejson=. Es el fallo número uno. Condata=el servidor recibe un formulario; conjson=recibe JSON. Si la documentación muestra un cuerpo entre llaves, quieresjson=. - Valores
Noneenparams. Requests descarta los parámetros cuyo valor esNone, algo cómodo para filtros opcionales, pero sorprendente si esperabas enviar un valor vacío. - Construir la URL a mano. Concatenar
"?buscar=" + textorompe cuando el texto lleva espacios, tildes o el símbolo&. Conparamsrequests los codifica correctamente. - Repetir cabeceras que requests ya gestiona. No hace falta que indiques
Content-Typecuando usasjson=niContent-Lengthen ningún caso.
Cuándo usar PUT, PATCH y DELETE
La elección entre métodos no es solo estilo: comunica la intención a la API. Usa POST para crear algo nuevo, PUT cuando envías el recurso completo para reemplazarlo y PATCH cuando solo cambias algunos campos. PUT y DELETE son idempotentes: repetirlos deja el servidor en el mismo estado, algo que importará cuando hablemos de reintentos en la Parte 4. POST, en cambio, normalmente no lo es: enviarlo dos veces puede crear dos recursos.
Siguiente parte
En la Parte 3 verás cómo evitar que tu script se cuelgue y cómo autenticarte.