Introducción
La versatilidad de Python se extiende al trabajo con datos JSON, un formato ampliamente utilizado para almacenar e intercambiar información. Las estructuras JSON pueden ser simples o complejas, con elementos anidados, de manera similar a los diccionarios y listas de Python. En este tutorial, aprenderá a acceder y extraer datos de estructuras JSON anidadas en Python a través de ejercicios prácticos.
Al final de este laboratorio, podrá navegar con confianza por objetos JSON, acceder a claves profundamente anidadas y trabajar con arrays anidados en aplicaciones Python.
Entendiendo JSON en Python
JSON (JavaScript Object Notation) es un formato ligero de intercambio de datos que es legible por humanos y analizable por máquinas. En Python, los objetos JSON se representan como diccionarios y los arrays JSON como listas.
Comencemos creando un script de Python simple para explorar datos JSON:
Abra el WebIDE y cree un nuevo archivo haciendo clic en "File > New File" desde el menú.
Guarde el archivo como
basic_json.pyen el directorio/home/labex/project/json_practice.Agregue el siguiente código a
basic_json.py:
import json
## A simple JSON object (represented as a Python dictionary)
person = {
"name": "John Doe",
"age": 30,
"email": "john.doe@example.com",
"is_employed": True,
"hobbies": ["reading", "hiking", "coding"]
}
## Convert Python dictionary to JSON string
json_string = json.dumps(person, indent=2)
print("JSON as string:")
print(json_string)
print("\n" + "-" * 50 + "\n")
## Convert JSON string back to Python dictionary
parsed_json = json.loads(json_string)
print("Python dictionary:")
print(parsed_json)
print("\n" + "-" * 50 + "\n")
## Accessing basic elements
print("Basic access examples:")
print(f"Name: {parsed_json['name']}")
print(f"Age: {parsed_json['age']}")
print(f"First hobby: {parsed_json['hobbies'][0]}")
- Ejecute el script abriendo una terminal en WebIDE y ejecutando:
cd /home/labex/project/json_practice
python3 basic_json.py
Debería ver la siguiente salida:
JSON as string:
{
"name": "John Doe",
"age": 30,
"email": "john.doe@example.com",
"is_employed": true,
"hobbies": [
"reading",
"hiking",
"coding"
]
}
--------------------------------------------------
Python dictionary:
{'name': 'John Doe', 'age': 30, 'email': 'john.doe@example.com', 'is_employed': True, 'hobbies': ['reading', 'hiking', 'coding']}
--------------------------------------------------
Basic access examples:
Name: John Doe
Age: 30
First hobby: reading
Entendiendo el Código
json.dumps()convierte un objeto Python a una cadena con formato JSONjson.loads()analiza una cadena JSON y la convierte en un objeto Python- Para acceder a elementos en un objeto JSON, use la sintaxis del diccionario:
nombre_del_objeto['clave'] - Para acceder a elementos en un array JSON, use la indexación de listas:
nombre_del_array[índice]
Este ejemplo demuestra las operaciones básicas para trabajar con JSON en Python. En el siguiente paso, exploraremos cómo acceder a estructuras JSON anidadas.
Accediendo a Claves de Diccionarios Anidados
Los objetos JSON a menudo contienen estructuras anidadas. En Python, podemos acceder a datos anidados usando múltiples corchetes o encadenando claves de diccionario.
Creemos un nuevo script para explorar objetos JSON anidados:
En el WebIDE, cree un nuevo archivo y guárdelo como
nested_dict.pyen el directorio/home/labex/project/json_practice.Agregue el siguiente código a
nested_dict.py:
import json
## JSON with nested object
user_data = {
"name": "John Doe",
"age": 30,
"contact": {
"email": "john.doe@example.com",
"phone": "555-1234",
"address": {
"street": "123 Main St",
"city": "Anytown",
"state": "CA",
"zip": "12345"
}
},
"preferences": {
"theme": "dark",
"notifications": True
}
}
## Let's prettify and print the JSON structure
print("Full JSON structure:")
print(json.dumps(user_data, indent=2))
print("\n" + "-" * 50 + "\n")
## Accessing nested elements
print("Accessing nested elements:")
print(f"Email: {user_data['contact']['email']}")
print(f"City: {user_data['contact']['address']['city']}")
print(f"Theme: {user_data['preferences']['theme']}")
print("\n" + "-" * 50 + "\n")
## Safe access with get() method
print("Safe access with get():")
## get() returns None if key doesn't exist, or a default value if specified
phone = user_data.get('contact', {}).get('phone', 'Not available')
country = user_data.get('contact', {}).get('address', {}).get('country', 'Not specified')
print(f"Phone: {phone}")
print(f"Country: {country}") ## This key doesn't exist but won't cause an error
- Ejecute el script en la terminal:
cd /home/labex/project/json_practice
python3 nested_dict.py
Debería ver una salida similar a:
Full JSON structure:
{
"name": "John Doe",
"age": 30,
"contact": {
"email": "john.doe@example.com",
"phone": "555-1234",
"address": {
"street": "123 Main St",
"city": "Anytown",
"state": "CA",
"zip": "12345"
}
},
"preferences": {
"theme": "dark",
"notifications": true
}
}
--------------------------------------------------
Accessing nested elements:
Email: john.doe@example.com
City: Anytown
Theme: dark
--------------------------------------------------
Safe access with get():
Phone: 555-1234
Country: Not specified
Entendiendo el Acceso Anidado
Cuando se trabaja con estructuras JSON anidadas, puede acceder a elementos anidados encadenando claves con corchetes:
## Syntax for nested access
value = json_data['key1']['key2']['key3']
Sin embargo, este enfoque puede causar errores si alguna clave en la cadena no existe. El método más seguro es usar la función get(), que le permite proporcionar un valor predeterminado si falta una clave:
## Safe access with get() method
value = json_data.get('key1', {}).get('key2', {}).get('key3', 'default_value')
Este patrón de acceso seguro es particularmente valioso cuando se trabaja con respuestas de API u otros datos JSON externos donde la estructura podría no ser consistente.
Trabajando con Arrays Anidados en JSON
Los datos JSON a menudo incluyen arrays (listas en Python) que pueden contener otros objetos o arrays. Exploremos cómo acceder a elementos dentro de arrays anidados.
En el WebIDE, cree un nuevo archivo y guárdelo como
nested_arrays.pyen el directorio/home/labex/project/json_practice.Agregue el siguiente código a
nested_arrays.py:
import json
## JSON with nested arrays
company_data = {
"name": "Tech Innovations Inc",
"founded": 2010,
"departments": [
{
"name": "Engineering",
"employees": [
{"name": "Alice Johnson", "role": "Software Engineer", "skills": ["Python", "JavaScript", "AWS"]},
{"name": "Bob Smith", "role": "DevOps Engineer", "skills": ["Docker", "Kubernetes", "Linux"]}
]
},
{
"name": "Marketing",
"employees": [
{"name": "Carol Williams", "role": "Marketing Manager", "skills": ["SEO", "Content Strategy"]},
{"name": "Dave Brown", "role": "Social Media Specialist", "skills": ["Facebook Ads", "Instagram"]}
]
}
],
"locations": ["San Francisco", "New York", "London"]
}
## Print the JSON structure
print("Company Data:")
print(json.dumps(company_data, indent=2))
print("\n" + "-" * 50 + "\n")
## Accessing elements in arrays
print("Accessing array elements:")
print(f"First location: {company_data['locations'][0]}")
print(f"Number of departments: {len(company_data['departments'])}")
print(f"First department name: {company_data['departments'][0]['name']}")
print("\n" + "-" * 50 + "\n")
## Iterating through nested arrays
print("All employees and their skills:")
for department in company_data['departments']:
dept_name = department['name']
print(f"\nDepartment: {dept_name}")
print("-" * 20)
for employee in department['employees']:
print(f" {employee['name']} ({employee['role']})")
print(f" Skills: {', '.join(employee['skills'])}")
print()
## Finding specific data in nested arrays
print("-" * 50 + "\n")
print("Finding employees with Python skills:")
for department in company_data['departments']:
for employee in department['employees']:
if "Python" in employee['skills']:
print(f" {employee['name']} in {department['name']} department")
- Ejecute el script en la terminal:
cd /home/labex/project/json_practice
python3 nested_arrays.py
Debería ver una salida similar a:
Company Data:
{
"name": "Tech Innovations Inc",
"founded": 2010,
"departments": [
{
"name": "Engineering",
"employees": [
{
"name": "Alice Johnson",
"role": "Software Engineer",
"skills": [
"Python",
"JavaScript",
"AWS"
]
},
{
"name": "Bob Smith",
"role": "DevOps Engineer",
"skills": [
"Docker",
"Kubernetes",
"Linux"
]
}
]
},
{
"name": "Marketing",
"employees": [
{
"name": "Carol Williams",
"role": "Marketing Manager",
"skills": [
"SEO",
"Content Strategy"
]
},
{
"name": "Dave Brown",
"role": "Social Media Specialist",
"skills": [
"Facebook Ads",
"Instagram"
]
}
]
}
],
"locations": [
"San Francisco",
"New York",
"London"
]
}
--------------------------------------------------
Accessing array elements:
First location: San Francisco
Number of departments: 2
First department name: Engineering
--------------------------------------------------
All employees and their skills:
Department: Engineering
--------------------
Alice Johnson (Software Engineer)
Skills: Python, JavaScript, AWS
Bob Smith (DevOps Engineer)
Skills: Docker, Kubernetes, Linux
Department: Marketing
--------------------
Carol Williams (Marketing Manager)
Skills: SEO, Content Strategy
Dave Brown (Social Media Specialist)
Skills: Facebook Ads, Instagram
--------------------------------------------------
Finding employees with Python skills:
Alice Johnson in Engineering department
Entendiendo el Acceso a Arrays Anidados
Trabajar con arrays anidados en JSON implica una combinación de:
- Acceso indexado: Use corchetes con un índice para acceder a elementos específicos del array (
array[0]) - Acceso a propiedades anidadas: Encadene claves de diccionario e índices de array (
data['departments'][0]['employees']) - Iteración: Use bucles para procesar múltiples elementos en arrays
El patrón más común para trabajar con arrays anidados es usar bucles for anidados:
for outer_item in json_data['outer_array']:
for inner_item in outer_item['inner_array']:
## Process the inner_item
print(inner_item['property'])
Este enfoque le permite atravesar estructuras anidadas complejas y extraer los datos específicos que necesita.
Manejo de Claves Faltantes y Prevención de Errores
Cuando se trabaja con estructuras JSON complejas, especialmente de fuentes externas como APIs, es importante manejar los posibles errores que surgen cuando faltan claves. Exploremos técnicas para acceder de forma segura a datos JSON anidados.
En el WebIDE, cree un nuevo archivo y guárdelo como
error_handling.pyen el directorio/home/labex/project/json_practice.Agregue el siguiente código a
error_handling.py:
import json
## JSON with inconsistent structure
api_response = {
"status": "success",
"data": {
"users": [
{
"id": 1,
"name": "John Doe",
"contact": {
"email": "john.doe@example.com",
"phone": "555-1234"
},
"roles": ["admin", "user"]
},
{
"id": 2,
"name": "Jane Smith",
## Missing contact info
"roles": ["user"]
},
{
"id": 3,
"name": "Bob Johnson",
"contact": {
## Only has email, no phone
"email": "bob.johnson@example.com"
}
## Missing roles
}
]
}
}
print("API Response Structure:")
print(json.dumps(api_response, indent=2))
print("\n" + "-" * 50 + "\n")
## Approach 1: Using try-except blocks
print("Method 1: Using try-except blocks")
print("-" * 30)
for user in api_response["data"]["users"]:
print(f"User: {user['name']}")
## Get email
try:
email = user['contact']['email']
print(f" Email: {email}")
except (KeyError, TypeError):
print(" Email: Not available")
## Get phone
try:
phone = user['contact']['phone']
print(f" Phone: {phone}")
except (KeyError, TypeError):
print(" Phone: Not available")
## Get roles
try:
roles = ", ".join(user['roles'])
print(f" Roles: {roles}")
except (KeyError, TypeError):
print(" Roles: None assigned")
print()
## Approach 2: Using get() method with defaults
print("\n" + "-" * 50 + "\n")
print("Method 2: Using get() method with defaults")
print("-" * 30)
for user in api_response["data"]["users"]:
print(f"User: {user['name']}")
## Get contact info with nested get() calls
contact = user.get('contact', {})
email = contact.get('email', 'Not available')
phone = contact.get('phone', 'Not available')
print(f" Email: {email}")
print(f" Phone: {phone}")
## Get roles with default empty list
roles = user.get('roles', [])
roles_str = ", ".join(roles) if roles else "None assigned"
print(f" Roles: {roles_str}")
print()
- Ejecute el script en la terminal:
cd /home/labex/project/json_practice
python3 error_handling.py
Debería ver una salida similar a:
API Response Structure:
{
"status": "success",
"data": {
"users": [
{
"id": 1,
"name": "John Doe",
"contact": {
"email": "john.doe@example.com",
"phone": "555-1234"
},
"roles": [
"admin",
"user"
]
},
{
"id": 2,
"name": "Jane Smith",
"roles": [
"user"
]
},
{
"id": 3,
"name": "Bob Johnson",
"contact": {
"email": "bob.johnson@example.com"
}
}
]
}
}
--------------------------------------------------
Method 1: Using try-except blocks
------------------------------
User: John Doe
Email: john.doe@example.com
Phone: 555-1234
Roles: admin, user
User: Jane Smith
Email: Not available
Phone: Not available
Roles: user
User: Bob Johnson
Email: bob.johnson@example.com
Phone: Not available
Roles: None assigned
--------------------------------------------------
Method 2: Using get() method with defaults
------------------------------
User: John Doe
Email: john.doe@example.com
Phone: 555-1234
Roles: admin, user
User: Jane Smith
Email: Not available
Phone: Not available
Roles: user
User: Bob Johnson
Email: bob.johnson@example.com
Phone: Not available
Roles: None assigned
Entendiendo las Técnicas de Manejo de Errores
El ejemplo demuestra dos enfoques principales para acceder de forma segura a datos JSON anidados:
Bloques Try-Except
- Envuelva el acceso potencialmente riesgoso en bloques try-except
- Capture KeyError (clave de diccionario faltante) y TypeError (intentar acceder a una clave en un no-diccionario)
- Proporcione valores de respaldo cuando ocurran errores
Método get() Encadenado
- Use el método get() del diccionario que toma un valor predeterminado como su segundo argumento
- Encadene múltiples llamadas get() para estructuras anidadas
- Proporciona un código más limpio sin manejo de excepciones
El enfoque del método get() generalmente se prefiere por su legibilidad y concisión al tratar con estructuras JSON anidadas. Le permite proporcionar valores predeterminados en cada nivel de anidamiento.
## Safe nested access pattern
value = data.get('level1', {}).get('level2', {}).get('level3', 'default_value')
Usar estas técnicas de manejo de errores hará que su código sea más robusto cuando trabaje con datos JSON de varias fuentes.
Ejercicio Práctico: Construyendo un Extractor de Datos JSON
Pongamos en práctica sus conocimientos creando un programa que extraiga información específica de una estructura JSON compleja. Esto podría representar un escenario del mundo real donde recibe datos JSON de una API y necesita procesarlos.
En el WebIDE, cree un nuevo archivo y guárdelo como
json_extractor.pyen el directorio/home/labex/project/json_practice.Agregue el siguiente código a
json_extractor.py:
import json
## A complex nested JSON structure (e.g., from a weather API)
weather_data = {
"location": {
"name": "New York",
"region": "New York",
"country": "United States of America",
"lat": 40.71,
"lon": -74.01,
"timezone": "America/New_York"
},
"current": {
"temp_c": 22.0,
"temp_f": 71.6,
"condition": {
"text": "Partly cloudy",
"icon": "//cdn.weatherapi.com/weather/64x64/day/116.png",
"code": 1003
},
"wind_mph": 6.9,
"wind_kph": 11.2,
"wind_dir": "ENE",
"humidity": 65,
"cloud": 75,
"feelslike_c": 22.0,
"feelslike_f": 71.6
},
"forecast": {
"forecastday": [
{
"date": "2023-09-20",
"day": {
"maxtemp_c": 24.3,
"maxtemp_f": 75.7,
"mintemp_c": 18.6,
"mintemp_f": 65.5,
"condition": {
"text": "Patchy rain possible",
"icon": "//cdn.weatherapi.com/weather/64x64/day/176.png",
"code": 1063
},
"daily_chance_of_rain": 85
},
"astro": {
"sunrise": "06:41 AM",
"sunset": "07:01 PM",
"moonrise": "10:15 AM",
"moonset": "08:52 PM"
},
"hour": [
{
"time": "2023-09-20 00:00",
"temp_c": 20.1,
"condition": {
"text": "Clear",
"icon": "//cdn.weatherapi.com/weather/64x64/night/113.png",
"code": 1000
},
"chance_of_rain": 0
},
{
"time": "2023-09-20 12:00",
"temp_c": 23.9,
"condition": {
"text": "Overcast",
"icon": "//cdn.weatherapi.com/weather/64x64/day/122.png",
"code": 1009
},
"chance_of_rain": 20
}
]
},
{
"date": "2023-09-21",
"day": {
"maxtemp_c": 21.2,
"maxtemp_f": 70.2,
"mintemp_c": 16.7,
"mintemp_f": 62.1,
"condition": {
"text": "Heavy rain",
"icon": "//cdn.weatherapi.com/weather/64x64/day/308.png",
"code": 1195
},
"daily_chance_of_rain": 92
},
"astro": {
"sunrise": "06:42 AM",
"sunset": "06:59 PM",
"moonrise": "11:30 AM",
"moonset": "09:15 PM"
}
}
]
}
}
def extract_weather_summary(data):
"""
Extract and format a weather summary from the provided data.
"""
try:
## Location information
location = data.get("location", {})
location_name = location.get("name", "Unknown")
country = location.get("country", "Unknown")
## Current weather
current = data.get("current", {})
temp_c = current.get("temp_c", "N/A")
temp_f = current.get("temp_f", "N/A")
condition = current.get("condition", {}).get("text", "Unknown")
humidity = current.get("humidity", "N/A")
## Forecast
forecast_days = data.get("forecast", {}).get("forecastday", [])
## Build summary string
summary = f"Weather Summary for {location_name}, {country}\n"
summary += f"==================================================\n\n"
summary += f"Current Conditions:\n"
summary += f" Temperature: {temp_c}°C ({temp_f}°F)\n"
summary += f" Condition: {condition}\n"
summary += f" Humidity: {humidity}%\n\n"
if forecast_days:
summary += "Forecast:\n"
for day_data in forecast_days:
date = day_data.get("date", "Unknown date")
day = day_data.get("day", {})
max_temp = day.get("maxtemp_c", "N/A")
min_temp = day.get("mintemp_c", "N/A")
condition = day.get("condition", {}).get("text", "Unknown")
rain_chance = day.get("daily_chance_of_rain", "N/A")
summary += f" {date}:\n"
summary += f" High: {max_temp}°C, Low: {min_temp}°C\n"
summary += f" Condition: {condition}\n"
summary += f" Chance of Rain: {rain_chance}%\n"
## Get sunrise and sunset times if available
astro = day_data.get("astro", {})
if astro:
sunrise = astro.get("sunrise", "N/A")
sunset = astro.get("sunset", "N/A")
summary += f" Sunrise: {sunrise}, Sunset: {sunset}\n"
summary += "\n"
return summary
except Exception as e:
return f"Error extracting weather data: {str(e)}"
## Print the full JSON data
print("Original Weather Data:")
print(json.dumps(weather_data, indent=2))
print("\n" + "-" * 60 + "\n")
## Extract and print the weather summary
weather_summary = extract_weather_summary(weather_data)
print(weather_summary)
## Save the summary to a file
with open("weather_summary.txt", "w") as file:
file.write(weather_summary)
print("\nWeather summary has been saved to 'weather_summary.txt'")
- Ejecute el script en la terminal:
cd /home/labex/project/json_practice
python3 json_extractor.py
- Después de ejecutar el script, puede ver el archivo de resumen generado:
cat weather_summary.txt
Verá el resumen del clima formateado extraído de la estructura JSON compleja.
Entendiendo el Extractor JSON
Este ejercicio práctico demuestra varios conceptos importantes para trabajar con datos JSON anidados:
Extracción segura de datos
- Usando el método
get()con valores predeterminados para manejar las claves faltantes - Accediendo a datos anidados con llamadas
get()encadenadas - Manejo de errores con bloques try-except
- Usando el método
Transformación de datos
- Convertir datos JSON a un formato legible por humanos
- Iterar a través de arrays anidados para procesar múltiples elementos
- Extraer solo la información relevante de una estructura compleja
Programación defensiva
- Anticipar y manejar posibles problemas
- Proporcionar valores predeterminados cuando faltan datos
- Capturar excepciones para evitar que el programa se bloquee
Este patrón de extracción, transformación y presentación de datos JSON es común en muchas aplicaciones del mundo real, como:
- Procesamiento de respuestas de API
- Generación de informes a partir de datos
- Filtrado y visualización de información para los usuarios
Siguiendo estos patrones, puede trabajar de forma fiable con datos JSON de cualquier complejidad.
Resumen
En este laboratorio, ha aprendido a trabajar con estructuras JSON anidadas en Python:
Manejo básico de JSON - Conversión entre objetos Python y cadenas JSON usando
json.dumps()yjson.loads().Acceso a claves de diccionarios anidados - Uso de la notación de corchetes encadenados para acceder a valores profundamente anidados en objetos JSON.
Trabajo con arrays anidados - Navegación y extracción de datos de arrays dentro de estructuras JSON usando indexación e iteración.
Técnicas de manejo de errores - Implementación de patrones de acceso seguro con bloques try-except y el método
get()para manejar claves faltantes.Extracción práctica de datos - Construcción de una aplicación completa que extrae, transforma y presenta datos de una estructura JSON compleja.
Estas habilidades son esenciales para trabajar con datos de APIs, archivos de configuración y otros escenarios de intercambio de datos. Ahora tiene la base para manejar con confianza datos JSON de cualquier complejidad en sus aplicaciones Python.
Para un aprendizaje adicional, considere explorar:
- Trabajar con APIs reales que devuelven datos JSON
- Usar bibliotecas como
pandaspara analizar datos JSON - Implementar la validación JSON con
jsonschema - Crear y manipular estructuras JSON personalizadas



