Чтение JSON в Python: что нужно знать заранее
Разбор модуля json из стандартной библиотеки: как прочитать файл и строку, чем json.load отличается от json.loads, как ловить ошибки разбора и работать с числами и кодировкой.

За полчаса вы научитесь читать JSON в Python: разбирать строку и файл, ловить ошибки в кривых данных и понимать, во что превращаются числа, null и true. Всё через стандартный модуль json — ставить ничего не нужно, он идёт с интерпретатором. Примеры проверены на Python 3.11 и 3.12, но работают начиная с 3.6.
Что нужно иметь до начала
- Python 3.6 или новее. Проверьте командой
python --version— должна вывестись строка видаPython 3.12.1. - Текстовый редактор или интерактивная оболочка (
pythonв терминале либо любой IDE). - Никаких сторонних пакетов:
jsonвходит в стандартную библиотеку.
Если планируете читать чужие данные из сети — держите в голове, что они могут прийти битыми. Обработку ошибок разберём отдельно.
Два разных входа: строка и файл
В модуле есть две функции чтения, и путать их — самая частая ошибка новичка.
json.loads(s)— читает строку (буква s в конце от string).json.load(f)— читает файловый объект, то есть то, что вернулopen().
Если передать в json.loads открытый файл, получите TypeError. Если передать в json.load строку — тоже ошибка. Запомните по букве s.
Шаг 1. Читаем JSON из строки
import json
# JSON пришёл как обычная строка Python
raw = '{"name": "Аня", "age": 30, "active": true, "tags": ["a", "b"]}'
data = json.loads(raw)
print(type(data)) # <class 'dict'>
print(data["name"]) # Аня
print(data["tags"]) # ['a', 'b']
Проверка: в консоли должно появиться <class 'dict'> и строка Аня. Значит, JSON разобран и превратился в словарь Python.
Шаг 2. Читаем JSON из файла
Пусть рядом со скриптом лежит файл config.json:
{
"host": "localhost",
"port": 5432,
"debug": false
}
Читаем его так:
import json
# encoding="utf-8" указываем явно: на Windows системная кодировка
# по умолчанию может быть cp1251, и кириллица прочитается неверно
with open("config.json", encoding="utf-8") as f:
config = json.load(f)
print(config["port"]) # 5432
print(config["debug"]) # False
Проверка: выведется 5432 и False. Обратите внимание — false из JSON стал питоновским False с большой буквы.
Во что превращаются типы
JSON и Python называют одни и те же вещи по-разному. Таблица соответствий — это то, что стоит держать перед глазами первое время.
| В JSON | Станет в Python |
|---|---|
object { } | dict |
array [ ] | list |
string "..." | str |
| number без точки | int |
| number с точкой или экспонентой | float |
true / false | True / False |
null | None |
Числа с дробной частью всегда становятсяfloat. Если в JSON лежит цена19.99, вы получите float со всеми его погрешностями округления. Для денег это может выйти боком — читайте про параметрparse_floatниже.
Обработка ошибок: данные бывают битыми
Если строка не является валидным JSON, обе функции бросают json.JSONDecodeError — это подкласс ValueError. Не оборачивайте чтение в голый except Exception: перехватывайте именно декодер, чтобы не глотать посторонние сбои.
import json
broken = '{"name": "Аня", "age": }' # после age нет значения
try:
data = json.loads(broken)
except json.JSONDecodeError as error:
# У ошибки есть удобные поля: строка, столбец и позиция символа
print(f"Не разобрать JSON: {error.msg}")
print(f"Строка {error.lineno}, столбец {error.colno}")
Проверка: скрипт не упадёт, а выведет сообщение об ошибке с номером строки и столбца. Это те же lineno, colno и pos, что описаны в документации класса — по ним удобно показывать пользователю, где именно сломался файл.
Файл может ещё и не открыться
При чтении из файла к JSONDecodeError добавляется FileNotFoundError — файла нет или путь неверный. Их стоит разделять:
import json
try:
with open("config.json", encoding="utf-8") as f:
config = json.load(f)
except FileNotFoundError:
print("Файл config.json не найден")
except json.JSONDecodeError as error:
print(f"Файл есть, но внутри не JSON: {error.msg}")
Полезные параметры, о которых редко пишут
У load и loads есть аргументы, которые решают частые задачи без ручного постпроцессинга.
parse_float — точные деньги вместо float
Чтобы дробные числа приходили как Decimal, а не float, передайте конструктор в parse_float:
import json
from decimal import Decimal
price_json = '{"price": 19.99}'
data = json.loads(price_json, parse_float=Decimal)
print(type(data["price"])) # <class 'decimal.Decimal'>
print(data["price"]) # 19.99 без погрешности float
Аналогично есть parse_int — на случай, если целые числа нужно обрабатывать особым образом.
object_pairs_hook — ловим дубли ключей
JSON допускает повторяющиеся ключи в объекте, а dict — нет: при разборе останется последнее значение, и вы молча потеряете данные. Если это критично, перехватите пары ключ-значение до сборки словаря через object_pairs_hook и решите, что с дублями делать.
Кодировка и BOM
Стандарт JSON предписывает UTF-8. Две ловушки на практике:
- На Windows
open()без явногоencodingберёт системную кодировку, а не UTF-8. Всегда пишитеencoding="utf-8"— тогда поведение одинаково на всех платформах. - Файл с BOM (метка порядка байтов в начале) свалит разбор с ошибкой в позиции 0. Открывайте такой файл с
encoding="utf-8-sig"— этот кодек съедает BOM автоматически.
Если не получилось
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)— чаще всего строка пустая, либо вы читаете HTML-страницу или сообщение об ошибке вместо JSON. Распечатайте первые символы:print(repr(raw[:50])).TypeError: the JSON object must be str, bytes or bytearray, not TextIOWrapper— вы передали вjson.loadsоткрытый файл. Нуженjson.load(без s).JSONDecodeError: Expecting property name enclosed in double quotes— в JSON одинарные кавычки или висячая запятая после последнего элемента. JSON требует двойных кавычек и запрещает запятую перед закрывающей скобкой. Это не Python-словарь, разбирать егоjson-ом нельзя.- Кириллица превратилась в кракозябры — файл прочитан не в UTF-8. Добавьте
encoding="utf-8"вopen(). JSONDecodeErrorв позиции 0 на первый взгляд валидного файла — в начале BOM. Откройте сencoding="utf-8-sig".
Что дальше
Когда чтение работает, следующий шаг — запись: функции json.dump и json.dumps с параметрами ensure_ascii=False (чтобы кириллица не превращалась в \uXXXX) и indent=2 (для читаемого форматирования). Если файлы большие (десятки мегабайт и больше), json.load держит весь объект в памяти целиком — тогда смотрите в сторону потоковых парсеров вроде ijson. А если данных много и важна скорость валидации схемы — это уже отдельная тема, здесь мы разбирали только базовое чтение.
Разбор научной статьи: Сложный текст — понятным языком, с терминами
Спросить за 12 ₽Источники: json — JSON encoder and decoder, документация Python
Частые вопросы
Чем json.load отличается от json.loads?
А если у меня старая версия Python?
Почему цена 19.99 из JSON считается неточно?
Как читать JSON, если я не уверен, что данные валидны?
JSON с кириллицей читается кракозябрами, что делать?
Можно ли прочитать JSON с одинарными кавычками?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.