Biblioteca Requests de Python: Guía completa de solicitudes HTTP en Python
Updated on
Hacer solicitudes HTTP en Python usando el módulo integrado urllib es famoso por ser complejo y verboso. Tienes que codificar parámetros manualmente, gestionar objetos de respuesta con múltiples llamadas a métodos y escribir decenas de líneas de código repetitivo solo para enviar una solicitud sencilla a una API. Esta complejidad ralentiza el desarrollo y hace que tu código sea más difícil de mantener.
La biblioteca requests de Python elimina esta frustración al proporcionar una API elegante y amigable para las personas para la comunicación HTTP. Ya sea que consumas APIs REST, hagas scraping de sitios web, subas archivos o construyas scripts de automatización, la biblioteca requests hace que las operaciones HTTP sean intuitivas y directas con solo unas pocas líneas de código.
En esta guía completa, aprenderás desde solicitudes GET y POST básicas hasta funciones avanzadas como autenticación, sesiones, manejo de errores y patrones reales de integración con APIs.
Instalación de la biblioteca Requests de Python
La biblioteca requests no forma parte de la biblioteca estándar de Python, así que necesitas instalarla por separado usando pip:
pip install requestsPara usuarios de conda:
conda install requestsUna vez instalada, puedes importarla en tus scripts de Python:
import requestsPara verificar la instalación y comprobar la versión:
import requests
print(requests.__version__)Hacer solicitudes GET con Python Requests
Las solicitudes GET son el método HTTP más común, usado para recuperar datos de servidores. La biblioteca requests hace que las solicitudes GET sean increíblemente simples.
Solicitud GET básica
Así es como se hace una solicitud GET básica:
import requests
response = requests.get('https://api.github.com')
print(response.status_code) # 200
print(response.text) # Response body as stringSolicitud GET con parámetros de consulta (query)
En lugar de construir manualmente URLs con query strings, usa el parámetro params:
import requests
# Method 1: Using params dictionary
params = {
'q': 'python requests',
'sort': 'stars',
'order': 'desc'
}
response = requests.get('https://api.github.com/search/repositories', params=params)
# The URL is automatically constructed:
# https://api.github.com/search/repositories?q=python+requests&sort=stars&order=desc
print(response.url) # View the constructed URL
data = response.json() # Parse JSON responseSolicitud GET con headers personalizados
Muchas APIs requieren headers personalizados para autenticación o negociación de contenido:
import requests
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Accept': 'application/json',
'Accept-Language': 'en-US,en;q=0.9'
}
response = requests.get('https://api.example.com/data', headers=headers)
print(response.json())Hacer solicitudes POST en Python
Las solicitudes POST envían datos a un servidor, comúnmente usadas para envíos de formularios y operaciones de API.
Solicitud POST con datos de formulario
Para enviar datos codificados como formulario (como envíos de formularios HTML):
import requests
# Send form data
data = {
'username': 'john_doe',
'password': 'secret123',
'remember_me': True
}
response = requests.post('https://example.com/login', data=data)
print(response.status_code)Solicitud POST con payload JSON
Las APIs REST modernas normalmente esperan payloads JSON. La biblioteca requests maneja la serialización JSON automáticamente:
import requests
# Method 1: Using json parameter (recommended)
payload = {
'name': 'New Project',
'description': 'A test project',
'tags': ['python', 'api']
}
response = requests.post('https://api.example.com/projects', json=payload)
# Method 2: Manual JSON encoding
import json
headers = {'Content-Type': 'application/json'}
response = requests.post(
'https://api.example.com/projects',
data=json.dumps(payload),
headers=headers
)Solicitud POST con archivos
Sube archivos usando el parámetro files:
import requests
# Upload a single file
files = {'file': open('report.pdf', 'rb')}
response = requests.post('https://example.com/upload', files=files)
# Upload multiple files
files = {
'file1': open('document.pdf', 'rb'),
'file2': open('image.jpg', 'rb')
}
response = requests.post('https://example.com/upload', files=files)
# Upload file with additional form data
files = {'file': open('data.csv', 'rb')}
data = {'description': 'Monthly report', 'category': 'finance'}
response = requests.post('https://example.com/upload', files=files, data=data)Otros métodos HTTP: PUT, PATCH, DELETE
La biblioteca requests soporta todos los métodos HTTP estándar:
import requests
# PUT - Replace entire resource
data = {'name': 'Updated Name', 'status': 'active'}
response = requests.put('https://api.example.com/users/123', json=data)
# PATCH - Partially update resource
data = {'status': 'inactive'}
response = requests.patch('https://api.example.com/users/123', json=data)
# DELETE - Remove resource
response = requests.delete('https://api.example.com/users/123')
print(response.status_code) # 204 No Content
# HEAD - Get headers only (no response body)
response = requests.head('https://example.com')
print(response.headers)
# OPTIONS - Get supported methods
response = requests.options('https://api.example.com/users')
print(response.headers.get('Allow'))Comprender el objeto Response
El objeto Response contiene toda la información sobre la respuesta del servidor:
import requests
response = requests.get('https://api.github.com/users/github')
# Status code
print(response.status_code) # 200, 404, 500, etc.
# Response body as string
print(response.text)
# Response body as JSON (for JSON APIs)
data = response.json()
print(data['login'])
# Raw binary content (for images, files)
image_data = response.content
with open('profile.jpg', 'wb') as f:
f.write(image_data)
# Response headers
print(response.headers)
print(response.headers['Content-Type'])
# Encoding
print(response.encoding) # 'utf-8'
# Request information
print(response.request.headers)
print(response.request.url)
# Check if request was successful
if response.ok: # True if status_code < 400
print("Success!")Trabajar con headers de solicitud
Los headers llevan metadatos importantes sobre la solicitud:
Establecer headers personalizados
import requests
headers = {
'User-Agent': 'MyApp/1.0',
'Accept': 'application/json',
'Accept-Encoding': 'gzip, deflate',
'Connection': 'keep-alive',
'Custom-Header': 'custom-value'
}
response = requests.get('https://api.example.com', headers=headers)Acceder a los headers de respuesta
import requests
response = requests.get('https://api.github.com')
# Dictionary-like access
print(response.headers['Content-Type'])
print(response.headers.get('X-RateLimit-Remaining'))
# Case-insensitive access
print(response.headers['content-type']) # Works!
# Iterate all headers
for key, value in response.headers.items():
print(f"{key}: {value}")Autenticación con Python Requests
La biblioteca requests soporta múltiples mecanismos de autenticación:
Autenticación básica (Basic)
import requests
from requests.auth import HTTPBasicAuth
# Method 1: Using auth parameter (recommended)
response = requests.get(
'https://api.example.com/protected',
auth=('username', 'password')
)
# Method 2: Explicit HTTPBasicAuth
response = requests.get(
'https://api.example.com/protected',
auth=HTTPBasicAuth('username', 'password')
)
# Method 3: Manual header (not recommended)
import base64
credentials = base64.b64encode(b'username:password').decode('utf-8')
headers = {'Authorization': f'Basic {credentials}'}
response = requests.get('https://api.example.com/protected', headers=headers)Autenticación con token Bearer
Común para tokens JWT y OAuth 2.0:
import requests
token = 'your_access_token_here'
headers = {'Authorization': f'Bearer {token}'}
response = requests.get('https://api.example.com/user', headers=headers)Autenticación con API Key
import requests
# Method 1: Query parameter
params = {'api_key': 'your_api_key_here'}
response = requests.get('https://api.example.com/data', params=params)
# Method 2: Custom header
headers = {'X-API-Key': 'your_api_key_here'}
response = requests.get('https://api.example.com/data', headers=headers)Autenticación OAuth 2.0
Para OAuth 2.0, usa la biblioteca requests-oauthlib:
from requests_oauthlib import OAuth2Session
client_id = 'your_client_id'
client_secret = 'your_client_secret'
token_url = 'https://oauth.example.com/token'
oauth = OAuth2Session(client_id)
token = oauth.fetch_token(token_url, client_secret=client_secret)
# Make authenticated requests
response = oauth.get('https://api.example.com/protected')Sesiones para conexiones persistentes
Las sesiones mantienen cookies, pooling de conexiones y configuración a través de múltiples solicitudes:
import requests
# Create a session
session = requests.Session()
# Set headers for all requests in this session
session.headers.update({
'User-Agent': 'MyApp/1.0',
'Accept': 'application/json'
})
# Login and session maintains cookies
login_data = {'username': 'john', 'password': 'secret'}
session.post('https://example.com/login', data=login_data)
# Subsequent requests use the session cookies
response1 = session.get('https://example.com/dashboard')
response2 = session.get('https://example.com/profile')
# Close the session
session.close()Sesión con autenticación
import requests
session = requests.Session()
session.auth = ('username', 'password')
# All requests in this session use the authentication
response1 = session.get('https://api.example.com/users')
response2 = session.get('https://api.example.com/posts')Context manager para sesiones
import requests
with requests.Session() as session:
session.headers.update({'Authorization': 'Bearer token123'})
response1 = session.get('https://api.example.com/data')
response2 = session.post('https://api.example.com/data', json={'key': 'value'})
# Session automatically closed after with blockEstrategias de timeout y reintento (retry)
Configura siempre timeouts para evitar que las solicitudes se queden colgadas indefinidamente:
Configurar timeouts
import requests
# Single timeout value (applies to both connect and read)
response = requests.get('https://api.example.com', timeout=5)
# Separate connect and read timeouts
response = requests.get('https://api.example.com', timeout=(3, 10))
# 3 seconds to establish connection, 10 seconds to read response
# No timeout (dangerous - may hang forever)
response = requests.get('https://api.example.com', timeout=None)Implementar lógica de reintentos (retry)
import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry
# Configure retry strategy
retry_strategy = Retry(
total=3, # Total number of retries
backoff_factor=1, # Wait 1, 2, 4 seconds between retries
status_forcelist=[429, 500, 502, 503, 504], # Retry on these status codes
allowed_methods=["HEAD", "GET", "OPTIONS", "POST"]
)
adapter = HTTPAdapter(max_retries=retry_strategy)
session = requests.Session()
session.mount("http://", adapter)
session.mount("https://", adapter)
# Requests will automatically retry on failure
response = session.get('https://api.example.com/data')Manejo de errores en Python Requests
Un manejo de errores robusto es crucial para aplicaciones en producción:
Manejar excepciones comunes
import requests
from requests.exceptions import (
ConnectionError,
Timeout,
HTTPError,
RequestException
)
try:
response = requests.get('https://api.example.com/data', timeout=5)
response.raise_for_status() # Raises HTTPError for 4xx/5xx status codes
data = response.json()
except ConnectionError:
print("Failed to connect to the server")
except Timeout:
print("Request timed out")
except HTTPError as e:
print(f"HTTP error occurred: {e}")
print(f"Status code: {e.response.status_code}")
except RequestException as e:
# Catches all requests exceptions
print(f"An error occurred: {e}")
except ValueError:
# JSON decoding error
print("Invalid JSON response")Comprobar códigos de estado
import requests
response = requests.get('https://api.example.com/data')
# Method 1: Manual check
if response.status_code == 200:
data = response.json()
elif response.status_code == 404:
print("Resource not found")
elif response.status_code >= 500:
print("Server error")
# Method 2: Using raise_for_status()
try:
response.raise_for_status()
data = response.json()
except requests.exceptions.HTTPError as e:
if response.status_code == 404:
print("Resource not found")
elif response.status_code == 401:
print("Authentication required")
else:
print(f"HTTP error: {e}")
# Method 3: Using response.ok
if response.ok: # True if status_code < 400
data = response.json()
else:
print(f"Request failed with status {response.status_code}")Verificación SSL y certificados
Por defecto, requests verifica los certificados SSL:
import requests
# Default behavior - verify SSL certificate
response = requests.get('https://api.example.com')
# Disable SSL verification (not recommended for production)
response = requests.get('https://example.com', verify=False)
# Suppress the InsecureRequestWarning
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
response = requests.get('https://example.com', verify=False)
# Use custom CA bundle
response = requests.get('https://example.com', verify='/path/to/ca_bundle.crt')
# Client-side certificates
response = requests.get(
'https://example.com',
cert=('/path/to/client.crt', '/path/to/client.key')
)Uso de proxies con Python Requests
Configura servidores proxy para las solicitudes:
import requests
# HTTP and HTTPS proxies
proxies = {
'http': 'http://10.10.1.10:3128',
'https': 'http://10.10.1.10:1080',
}
response = requests.get('https://api.example.com', proxies=proxies)
# SOCKS proxy (requires requests[socks])
proxies = {
'http': 'socks5://user:pass@host:port',
'https': 'socks5://user:pass@host:port'
}
# Use environment variables
# Set HTTP_PROXY and HTTPS_PROXY environment variables
response = requests.get('https://api.example.com') # Automatically uses env proxies
# Disable proxies
response = requests.get('https://api.example.com', proxies={'http': None, 'https': None})Comparación de bibliotecas HTTP en Python
Así es como la biblioteca requests se compara con alternativas:
| Feature | requests | urllib | httpx | aiohttp |
|---|---|---|---|---|
| Ease of Use | Excellent (Pythonic API) | Poor (verbose) | Excellent | Good |
| Async Support | No | No | Yes | Yes |
| HTTP/2 Support | No | No | Yes | No |
| Session Management | Built-in | Manual | Built-in | Built-in |
| JSON Handling | Automatic | Manual | Automatic | Automatic |
| Connection Pooling | Yes | No | Yes | Yes |
| Standard Library | No (pip install) | Yes | No (pip install) | No (pip install) |
| Documentation | Excellent | Good | Excellent | Good |
| Performance | Good | Fair | Excellent | Excellent (async) |
| SSL/TLS | Full support | Full support | Full support | Full support |
| Best For | Synchronous HTTP, general use | Simple scripts, no dependencies | Modern sync/async HTTP | High-performance async |
Cuándo usar cada una:
- requests: Opción por defecto para la mayoría de operaciones HTTP síncronas. Ideal para web scraping, consumo de APIs y tareas HTTP generales.
- urllib: Solo cuando no puedes instalar paquetes externos (requisito de biblioteca estándar).
- httpx: Cuando necesitas soporte HTTP/2 o quieres una API moderna compatible con requests con capacidades async.
- aiohttp: Para aplicaciones asíncronas de alto rendimiento que manejan muchas solicitudes concurrentes.
Rate limiting y scraping responsable
Al hacer scraping de sitios web o llamar APIs, implementa rate limiting:
import requests
import time
from datetime import datetime
class RateLimitedSession:
def __init__(self, requests_per_second=1):
self.session = requests.Session()
self.min_interval = 1.0 / requests_per_second
self.last_request_time = 0
def get(self, url, **kwargs):
# Wait if necessary
elapsed = time.time() - self.last_request_time
if elapsed < self.min_interval:
time.sleep(self.min_interval - elapsed)
# Make request
response = self.session.get(url, **kwargs)
self.last_request_time = time.time()
return response
# Use rate-limited session
session = RateLimitedSession(requests_per_second=2) # 2 requests per second
urls = ['https://api.example.com/item/1', 'https://api.example.com/item/2']
for url in urls:
response = session.get(url)
print(f"{datetime.now()}: {response.status_code}")Respetar robots.txt
import requests
from urllib.robotparser import RobotFileParser
def can_fetch(url, user_agent='MyBot'):
"""Check if URL can be scraped according to robots.txt"""
rp = RobotFileParser()
robots_url = f"{url.split('/')[0]}//{url.split('/')[2]}/robots.txt"
rp.set_url(robots_url)
rp.read()
return rp.can_fetch(user_agent, url)
url = 'https://example.com/page'
if can_fetch(url):
response = requests.get(url)
else:
print("Scraping not allowed by robots.txt")Ejemplos reales y casos de uso
Ejemplo 1: Consumir una API REST
import requests
class GitHubAPI:
def __init__(self, token=None):
self.base_url = 'https://api.github.com'
self.session = requests.Session()
if token:
self.session.headers.update({'Authorization': f'token {token}'})
def get_user(self, username):
"""Get user information"""
response = self.session.get(f'{self.base_url}/users/{username}')
response.raise_for_status()
return response.json()
def search_repositories(self, query, sort='stars', limit=10):
"""Search repositories"""
params = {'q': query, 'sort': sort, 'per_page': limit}
response = self.session.get(f'{self.base_url}/search/repositories', params=params)
response.raise_for_status()
return response.json()['items']
def create_issue(self, owner, repo, title, body):
"""Create an issue in a repository"""
url = f'{self.base_url}/repos/{owner}/{repo}/issues'
data = {'title': title, 'body': body}
response = self.session.post(url, json=data)
response.raise_for_status()
return response.json()
# Usage
api = GitHubAPI(token='your_github_token')
user = api.get_user('torvalds')
print(f"Name: {user['name']}, Followers: {user['followers']}")
repos = api.search_repositories('python requests', limit=5)
for repo in repos:
print(f"{repo['full_name']}: {repo['stargazers_count']} stars")Ejemplo 2: Descargar archivos con progreso
import requests
from tqdm import tqdm
def download_file(url, filename):
"""Download file with progress bar"""
response = requests.get(url, stream=True)
response.raise_for_status()
total_size = int(response.headers.get('content-length', 0))
with open(filename, 'wb') as f, tqdm(
desc=filename,
total=total_size,
unit='B',
unit_scale=True,
unit_divisor=1024,
) as progress_bar:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
progress_bar.update(len(chunk))
# Download a file
download_file('https://example.com/large-file.zip', 'downloaded.zip')Ejemplo 3: Web scraping con manejo de errores
import requests
from bs4 import BeautifulSoup
import time
def scrape_articles(base_url, max_pages=5):
"""Scrape article titles from a news website"""
session = requests.Session()
session.headers.update({
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
})
articles = []
for page in range(1, max_pages + 1):
try:
url = f"{base_url}?page={page}"
response = session.get(url, timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.content, 'html.parser')
titles = soup.find_all('h2', class_='article-title')
for title in titles:
articles.append({
'title': title.text.strip(),
'url': title.find('a')['href'] if title.find('a') else None
})
print(f"Scraped page {page}: {len(titles)} articles")
time.sleep(1) # Rate limiting
except requests.exceptions.RequestException as e:
print(f"Error scraping page {page}: {e}")
continue
return articles
# Usage
articles = scrape_articles('https://news.example.com/articles', max_pages=3)
print(f"Total articles collected: {len(articles)}")Ejemplo 4: Integración de API con paginación
import requests
def fetch_all_items(api_url, headers=None):
"""Fetch all items from a paginated API"""
items = []
page = 1
while True:
try:
params = {'page': page, 'per_page': 100}
response = requests.get(api_url, params=params, headers=headers, timeout=10)
response.raise_for_status()
data = response.json()
if not data: # No more items
break
items.extend(data)
print(f"Fetched page {page}: {len(data)} items")
page += 1
# Check for pagination in headers
if 'Link' in response.headers:
links = response.headers['Link']
if 'rel="next"' not in links:
break
except requests.exceptions.RequestException as e:
print(f"Error fetching page {page}: {e}")
break
return items
# Usage
all_items = fetch_all_items('https://api.example.com/items')
print(f"Total items: {len(all_items)}")Probar APIs en Jupyter con RunCell
Al desarrollar y probar integraciones con APIs, RunCell (opens in a new tab) proporciona un entorno de agente impulsado por IA directamente en notebooks de Jupyter. En lugar de depurar manualmente solicitudes y respuestas HTTP, el agente inteligente de RunCell puede ayudarte a:
- Construir y probar automáticamente solicitudes de API con la autenticación adecuada
- Depurar el parseo de respuestas y el manejo de errores en tiempo real
- Generar fragmentos de código para patrones HTTP comunes
- Validar respuestas de API contra esquemas esperados
- Iterar rápidamente sobre transformaciones de datos a partir de respuestas de API
Esto es especialmente valioso al trabajar con APIs complejas que requieren múltiples pasos de autenticación, manejo de paginación o lógica de parseo de datos intrincada. RunCell acelera el flujo de trabajo de desarrollo al reducir el ida y vuelta de probar solicitudes HTTP manualmente.
Preguntas frecuentes (FAQ)
¿Para qué se usa la biblioteca requests de Python?
La biblioteca requests de Python se utiliza para hacer solicitudes HTTP a servidores web y APIs. Simplifica tareas como obtener páginas web, consumir APIs REST, enviar datos de formularios, subir archivos y manejar autenticación. Es la biblioteca HTTP más popular en Python debido a su API intuitiva y su conjunto completo de funcionalidades.
¿Cómo instalo la biblioteca requests de Python?
Instala la biblioteca requests usando pip: pip install requests. Para entornos conda, usa conda install requests. Una vez instalada, impórtala con import requests en tu código Python. La biblioteca no forma parte de la biblioteca estándar de Python, por lo que se requiere instalación.
¿Cuál es la diferencia entre requests.get() y requests.post()?
requests.get() recupera datos de un servidor sin modificar nada, y normalmente se usa para obtener páginas web o datos de APIs. requests.post() envía datos al servidor para crear o actualizar recursos, comúnmente usado para envíos de formularios, carga de archivos u operaciones de API que modifican el estado del servidor. Las solicitudes GET pasan parámetros en la URL, mientras que las POST envían datos en el cuerpo de la solicitud.
¿Cómo manejo errores con la biblioteca requests de Python?
Usa bloques try-except para capturar excepciones de requests: ConnectionError para problemas de red, Timeout para respuestas lentas, HTTPError para códigos 4xx/5xx y RequestException como captura general. Llama a response.raise_for_status() después de cada solicitud para lanzar automáticamente HTTPError cuando la solicitud falle. Configura siempre timeouts para evitar que las solicitudes queden colgadas indefinidamente.
¿Cómo envío datos JSON con Python requests?
Usa el parámetro json en requests: requests.post(url, json=data). La biblioteca serializa automáticamente diccionarios de Python a JSON y establece el header Content-Type: application/json. Para parsear respuestas JSON, usa response.json(), que deserializa el cuerpo de la respuesta JSON en un diccionario de Python.
¿Debería usar requests o urllib en Python?
Usa la biblioteca requests para la mayoría de operaciones HTTP. Ofrece una API más limpia, manejo automático de JSON, gestión de sesiones integrada y mejor manejo de errores comparado con urllib. Usa urllib solo cuando no puedas instalar paquetes externos y debas depender exclusivamente de la biblioteca estándar de Python. Para aplicaciones modernas que requieren HTTP/2 o soporte async, considera httpx como alternativa.
¿Cómo agrego autenticación a Python requests?
Para autenticación Basic, usa requests.get(url, auth=('username', 'password')). Para tokens Bearer (JWT, OAuth), añade un header Authorization: headers = {'Authorization': f'Bearer {token}'}. Para API keys, agrégalas como parámetros de consulta usando el diccionario params o como headers personalizados como 'X-API-Key'. Las sesiones pueden mantener la autenticación entre múltiples solicitudes.
¿Qué son las sesiones en Python requests y cuándo debería usarlas?
Las sesiones mantienen configuración (headers, cookies, autenticación) a través de múltiples solicitudes al mismo servidor. Usa sesiones cuando hagas varias solicitudes a una API, cuando necesites mantener estado de inicio de sesión con cookies o cuando quieras reutilizar conexiones TCP para mejor rendimiento. Crea una sesión con session = requests.Session() y usa session.get() en lugar de requests.get().
Conclusión
La biblioteca requests de Python es una herramienta indispensable para la comunicación HTTP en Python. Su API elegante transforma operaciones HTTP complejas en código simple y legible. Desde solicitudes GET básicas hasta funciones avanzadas como autenticación, sesiones, carga de archivos y manejo de errores, requests proporciona todo lo que necesitas para interacciones HTTP robustas.
Al dominar los patrones y buenas prácticas de esta guía—configurar timeouts, implementar lógica de reintentos, manejar errores con elegancia y respetar límites de tasa—construirás aplicaciones confiables que se comunican eficazmente con servicios web y APIs. Ya sea que consumas APIs REST, hagas scraping de sitios web o construyas herramientas de automatización, la biblioteca requests hace que las operaciones HTTP sean directas y mantenibles.