Парсинг JSON

Разбор JSON во всех деталях: вложенные структуры, стриминг больших файлов, JSONPath и типичные ошибки при работе с API.

КP
Команда Parsing.agency
Сбор данных под задачи бизнеса
Опубликовано: 16 марта 2025

Что такое JSON

JSON (JavaScript Object Notation) — это текстовый формат обмена данными, удобный одновременно для чтения человеком и для обработки машиной. Несмотря на происхождение из JavaScript, формат давно стал языконезависимым стандартом и используется практически везде, где приложениям нужно обмениваться структурированными данными.

Базовый пример JSON-документа:

json
{
  "id": 42,
  "name": "Анна",
  "is_active": true,
  "roles": ["admin", "editor"],
  "profile": {
    "city": "Тбилиси",
    "age": 29
  }
}

Формат строится из нескольких простых типов: объекты (пары «ключ — значение»), массивы, строки, числа, логические значения и null. Эта простота и стала причиной его повсеместного распространения.

Что такое парсинг JSON и зачем он нужен

Парсинг JSON (разбор) — это процесс преобразования JSON-текста в структуру данных, понятную конкретному языку программирования: объект, словарь, массив, список и т. д. По сути парсер берёт строку символов и превращает её в живые объекты, с которыми можно работать в коде.

Обратный процесс — превращение объектов программы обратно в JSON-строку — называется сериализацией (или маршалингом). Парсинг и сериализация почти всегда идут парой.

Парсинг нужен в типичных задачах:

  • Работа с API — получение и отправка данных по HTTP (об этом подробнее ниже).
  • Конфигурационные файлы — многие инструменты хранят настройки в JSON (package.json, tsconfig.json и др.).
  • Хранение и обмен данными — логи, сообщения в очередях (Kafka, RabbitMQ), документы в NoSQL-базах (MongoDB).
  • Межсервисное взаимодействие в микросервисной архитектуре.
  • Сохранение состояния приложения в файлы или localStorage в браузере.

Парсинг JSON при работе с API

Самый частый сценарий, в котором разработчик сталкивается с парсингом JSON, — это взаимодействие с API. Подавляющее большинство современных веб-API (REST, а нередко и другие стили) обмениваются данными именно в формате JSON.

Типичный цикл работы с API выглядит так:

  1. Клиент отправляет HTTP-запрос на эндпоинт API.
  2. Сервер отвечает телом ответа в виде JSON-строки.
  3. Клиент парсит эту строку, превращая её в объекты, и работает с данными дальше.
  4. При отправке данных (POST, PUT) клиент, наоборот, сериализует свои объекты в JSON.

Без шага парсинга ответ сервера остаётся просто текстом, с которым нельзя удобно работать программно. Поэтому парсинг — обязательное звено почти в любой интеграции с внешним сервисом.

См. также: материал «Парсинг API» — там подробно разбирается, как устроены запросы к API, как обрабатывать ответы, работать с заголовками, статус-кодами, пагинацией и аутентификацией. Настоящая статья сосредоточена именно на этапе разбора самих JSON-данных, который является составной частью этого процесса.

Примеры реализации парсинга JSON на разных языках

Ниже приведены примеры разбора JSON в популярных языках. В каждом случае разбирается одна и та же строка, а затем извлекается значение вложенного поля.

Python

В стандартной библиотеке есть модуль json. Метод loads разбирает строку, load — содержимое файла.

python
import json

data_str = '{"name": "Анна", "profile": {"city": "Тбилиси", "age": 29}}'

# Парсинг строки в словарь
data = json.loads(data_str)

print(data["name"])              # Анна
print(data["profile"]["city"])   # Тбилиси

# Обратная операция — сериализация
back_to_str = json.dumps(data, ensure_ascii=False)

JavaScript

В JavaScript парсинг встроен в язык через глобальный объект JSON. Это и есть «родной» формат экосистемы.

javascript
const dataStr = '{"name": "Анна", "profile": {"city": "Тбилиси", "age": 29}}';

// Парсинг строки в объект
const data = JSON.parse(dataStr);

console.log(data.name);            // Анна
console.log(data.profile.city);    // Тбилиси

// Обратная операция
const backToStr = JSON.stringify(data);

При работе с fetch парсинг ответа API делается одной строкой:

javascript
const response = await fetch("https://api.example.com/users/42");
const user = await response.json(); // ответ уже распарсен в объект
console.log(user.name);

Java

В стандартной библиотеке нет встроенного парсера, поэтому обычно используют библиотеки — например, Jackson или Gson. Пример с Jackson:

java
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public class Main {
    public static void main(String[] args) throws Exception {
        String dataStr = "{\"name\": \"Анна\", \"profile\": {\"city\": \"Тбилиси\"}}";

        ObjectMapper mapper = new ObjectMapper();
        JsonNode node = mapper.readTree(dataStr);

        System.out.println(node.get("name").asText());                  // Анна
        System.out.println(node.get("profile").get("city").asText());   // Тбилиси
    }
}

Чаще JSON разбирают сразу в типизированный класс (POJO):

java
record Profile(String city, int age) {}
record User(String name, Profile profile) {}

User user = mapper.readValue(dataStr, User.class);
System.out.println(user.profile().city());

Go

В стандартной библиотеке есть пакет encoding/json. Данные обычно разбирают в структуру с тегами полей.

go
package main

import (
    "encoding/json"
    "fmt"
)

type Profile struct {
    City string `json:"city"`
    Age  int    `json:"age"`
}

type User struct {
    Name    string  `json:"name"`
    Profile Profile `json:"profile"`
}

func main() {
    dataStr := `{"name": "Анна", "profile": {"city": "Тбилиси", "age": 29}}`

    var user User
    json.Unmarshal([]byte(dataStr), &user)

    fmt.Println(user.Name)          // Анна
    fmt.Println(user.Profile.City)  // Тбилиси
}

C

В современном .NET есть встроенное пространство имён System.Text.Json.

c#
using System;
using System.Text.Json;

class Program
{
    static void Main()
    {
        string dataStr = "{\"name\": \"Анна\", \"profile\": {\"city\": \"Тбилиси\"}}";

        using JsonDocument doc = JsonDocument.Parse(dataStr);
        JsonElement root = doc.RootElement;

        Console.WriteLine(root.GetProperty("name").GetString());                       // Анна
        Console.WriteLine(root.GetProperty("profile").GetProperty("city").GetString()); // Тбилиси
    }
}

PHP

В PHP парсинг встроен в язык через функции json_decode и json_encode.

php
<?php
$dataStr = '{"name": "Анна", "profile": {"city": "Тбилиси", "age": 29}}';

// true — разбирать в ассоциативный массив, а не в объект
$data = json_decode($dataStr, true);

echo $data["name"];             // Анна
echo $data["profile"]["city"];  // Тбилиси

// Обратная операция
$backToStr = json_encode($data, JSON_UNESCAPED_UNICODE);

Rust

В экосистеме Rust де-факто стандартом является крейт serde вместе с serde_json.

rust
use serde::Deserialize;

#[derive(Deserialize)]
struct Profile {
    city: String,
    age: u32,
}

#[derive(Deserialize)]
struct User {
    name: String,
    profile: Profile,
}

fn main() {
    let data_str = r#"{"name": "Анна", "profile": {"city": "Тбилиси", "age": 29}}"#;

    let user: User = serde_json::from_str(data_str).unwrap();

    println!("{}", user.name);          // Анна
    println!("{}", user.profile.city);  // Тбилиси
}

Сравнение подходов

Язык Инструмент Встроен в язык
Python json Да
JavaScript JSON Да
Java Jackson / Gson Нет
Go encoding/json Да
C# System.Text.Json Да
PHP json_decode Да
Rust serde / serde_json Нет

Заметно два основных подхода к разбору:

  • Динамический разбор — JSON превращается в универсальную структуру (словарь, массив, дерево узлов). Удобно для быстрой и гибкой работы, но без проверки типов на этапе компиляции.
  • Типизированный разбор — JSON сразу отображается в заранее описанные классы или структуры. Безопаснее и нагляднее, особенно в строго типизированных языках (Java, Go, Rust, C#).

Частые проблемы и рекомендации

При парсинге JSON стоит учитывать несколько типичных сложностей:

  • Невалидный JSON. Если строка повреждена или содержит синтаксические ошибки, парсер выбросит исключение. Разбор внешних данных всегда стоит оборачивать в обработку ошибок.
  • Отсутствующие или null-поля. Не предполагайте, что все ожидаемые ключи всегда присутствуют, — API может прислать неполный объект. Проверяйте наличие полей перед обращением.
  • Кодировка. JSON по стандарту использует UTF-8. В некоторых языках (Python, PHP) нужно явно указывать флаги, чтобы кириллица не превращалась в \u-последовательности при сериализации.
  • Большие документы. Для очень больших файлов вместо загрузки всего объекта в память применяют потоковый (streaming) разбор, читающий данные по частям.
  • Числа и точность. Большие целые числа и числа с плавающей точкой могут терять точность — для финансовых данных это критично, и их иногда передают строками.

Итог

Парсинг JSON — это базовый навык, без которого почти невозможна работа с современными API и обмен данными между системами. Сам формат универсален, а инструменты для его разбора есть в каждом распространённом языке программирования: где-то встроенные, где-то в виде популярных библиотек. Принцип везде одинаков — превратить текстовую строку в удобные для кода объекты, а при необходимости проделать обратный путь.

Чтобы увидеть, как парсинг встраивается в полный цикл взаимодействия с внешними сервисами, обратитесь к материалу «Парсинг API».