Skip to main content

Yandex Bookmate API

Неофициальный Python-клиент для Яндекс Книг / Bookmate. Python 3.9 и новее.

Клиент предоставляет синхронные и асинхронные методы REST и GraphQL API. Без токена доступны публичные сведения о книгах и пользователях; личная библиотека, профиль и другие приватные данные требуют OAuth-токена.

Установка

pip install yandex-book-api

Для асинхронного клиента:

pip install "yandex-book-api[async]"

Зависимости устанавливаются автоматически из pyproject.toml: requests, для Python младше 3.11 — typing_extensions. Async-дополнение устанавливает aiohttp и aiofiles. Отдельный requirements.txt не требуется.

Для разработки из клонированного репозитория:

python -m pip install -e ".[dev,async]"

Получение токена

Команда авторизации

После установки библиотеки выполните:

yandex-book-token

Либо запустите модуль:

python -m yandex_book.auth

При работе из репозитория также доступен python get_token.py. Для этого способа используются только стандартные модули Python.

На macOS команда открывает Safari и до 180 секунд ждёт токен в URL активной вкладки. Не переключайтесь с вкладки авторизации до получения результата. Если macOS запросит доступ, разрешите процессу, из которого запущен скрипт, управлять Safari.

На Windows и Linux команда открывает браузер по умолчанию и просит вставить полную ссылку возврата из адресной строки. На macOS ручной ввод используется, если токен не удалось получить автоматически. Страница с сообщением об ошибке открытия Букмейта может содержать токен в своём URL — скопируйте адрес целиком. Используйте вкладку, открытую текущим запуском команды: скрипт проверяет домен возврата и случайный параметр state. Ссылка предыдущего запуска и отдельно скопированный токен не принимаются. Если браузер не открылся, скрипт выведет ссылку для текущего запуска; откройте именно её.

Принудительный ручной режим и настройка ожидания:

yandex-book-token --manual
yandex-book-token --timeout 60

Результат — OAuth-токен, обычно начинающийся с y0_. Команда выводит его в консоль и не сохраняет в файл. Дополнительные Python-пакеты для авторизации не нужны; автоматическое чтение Safari использует системную команду macOS osascript.

Вручную через браузер

Откройте страницу авторизации Яндекса и войдите в аккаунт. После перенаправления скопируйте значение access_token из URL: оно находится после #access_token= и заканчивается перед следующим &. Если токена нет в адресе, используйте команду авторизации.

Токен передаётся в YandexBookClient(token); не публикуйте его и не добавляйте в Git.

Быстрый старт

Публичные данные:

from yandex_book import YandexBookClient

with YandexBookClient() as client:
    book = client.get_book("mqK3FFjg")
    if book is not None:
        print(book.display_title)
        if book.cover is not None and book.cover.best_url:
            client.download_file(book.cover.best_url, "cover.jpg")

Профиль и личная библиотека:

import os
from yandex_book import YandexBookClient

with YandexBookClient(os.environ["YANDEX_BOOK_TOKEN"]) as client:
    me = client.get_profile()
    if me is not None:
        print(me.name, me.login, me.id)
    for card in client.get_my_library(page=1, per_page=10):
        if card.book is not None:
            print(card.book.display_title, card.state)

Профиль возвращается как User | None, библиотека — как список LibraryCard. add_book(book_uuid) возвращает LibraryCard | None, а remove_book(library_card_uuid) — True после успешного HTTP-запроса. Получение книги или пользователя возвращает модель либо None, если ответ не содержит соответствующего объекта. HTTP 404 вызывает NotFoundError.

Асинхронный клиент и закрытие сессий

import asyncio
import os
from yandex_book import YandexBookClientAsync

async def main():
    async with YandexBookClientAsync(os.environ["YANDEX_BOOK_TOKEN"]) as client:
        me = await client.get_profile()
        if me is not None:
            books = await client.get_user_books(me.login)
            print(f"{me.name}: {len(books)} книг")

asyncio.run(main())

Без контекстного менеджера вызывайте client.close() или await client.close() в finally. Контекстный менеджер закрывает HTTP-сессию и при исключении. После закрытия клиент не принимает новые запросы; создайте новый экземпляр. Скачивание выполняется порциями; асинхронный клиент записывает файл через aiofiles. Каталог назначения создаётся автоматически. Файл сначала записывается во временный файл рядом с назначением и заменяет его только после успешного завершения загрузки. При обрыве существующий файл сохраняется. Auth-Token передаётся только адресам API, включая проверку каждого HTTP-перенаправления. При настройке собственных base_url или graphql_url их адреса также считаются доверенными.

Методы клиента

Ниже приведены сигнатуры синхронного клиента. Асинхронный клиент предоставляет те же методы с await, кроме конструктора; для контекстного менеджера используется async with. init() загружает профиль в client.me и заполняет client.account_login. account_uuid сохранён для совместимости; использовать его в пользовательских маршрутах не следует.

Метод Возвращает
close() None
init() 'YandexBookClient'
get_profile() Optional[User]
get_counters() Dict[str, Any]
get_notifications_status() Dict[str, Any]
get_access_levels() Dict[str, Any]
get_privacy_settings() Dict[str, Any]
get_sync_state() Dict[str, Any]
get_context() Dict[str, Any]
get_metadata_secret() Dict[str, Any]
get_user_json() Dict[str, Any]
get_push_notification_restrictions() Dict[str, Any]
get_features(feature_names: Optional[List[str]]=None) Dict[str, Any]
get_user(user_id: Union[int, str]) Optional[User]
get_user_books(user_id: Union[int, str]) List[Book]
get_user_audiobooks(user_id: Union[int, str]) List[Audiobook]
get_user_comics(user_id: Union[int, str]) List[Comicbook]
get_user_bookshelves(user_id: Union[int, str]) List[Bookshelf]
get_user_followings(user_id: Union[int, str]) List[User]
get_user_impressions(user_id: Union[int, str]) List[Impression]
get_user_quotes(user_id: Union[int, str]) List[Quote]
get_user_reading_achievements(user_id: Union[int, str]) Устарел: EndpointGoneError при HTTP 410
get_person_books(person_id: str, role: str = 'author', page: int = 1, per_page: int = 20) List[Book]
get_book(book_id: str) Optional[Book]
get_book_impressions(book_id: str) List[Impression]
get_audiobook(audiobook_id: str) Optional[Audiobook]
get_audiobook_impressions(audiobook_id: str) List[Impression]
get_comicbook(comic_id: str) Optional[Comicbook]
get_comicbook_impressions(comic_id: str) List[Impression]
get_my_library(limit: Optional[int]=None, offset: Optional[int]=None, *, page: Optional[int]=None, per_page: Optional[int]=None) List[LibraryCard]
add_book(book_uuid: str) Optional[LibraryCard]
remove_book(library_card_uuid: str) bool
get_my_bookshelves(page: int=1, per_page: int=20) List[Bookshelf]
get_bookshelf_books(bookshelf_uuid: str) List[Book]
get_series_following(user_id: Optional[Union[int, str]]=None, page: int=1, per_page: int=20) Dict[str, Any]
get_reading_achievements(year: Optional[int]=None) Устарел: EndpointGoneError при HTTP 410
get_emotions() Dict[str, Any]
get_popular_searches(language: str='ru', page: int=1) Dict[str, Any]
search(query: str, no_misspell: bool=False, types: Optional[List[str]]=None, cursor: str='') Dict[str, Any]
get_subscriptions(cursor: str='', per_page: int=20) Dict[str, Any]
get_reading_statistics(request_time: Optional[str]=None) Dict[str, Any]
test_token() bool
download_file(url: str, filepath: str) None
search_books(query: str, no_misspell: bool=False, types: Optional[List[str]]=None, cursor: str='') Dict[str, Any]

Параметр user_id в методах get_user_* сохранён по имени для совместимости, но основной идентификатор — логин (User.login). Числовой ID поддерживается только для текущего аккаунта с токеном: клиент загружает профиль и определяет логин. Для чужого числового ID передайте логин явно. Строки считаются логинами; User.uuid не используется как идентификатор маршрута. Модельные методы user.fetch_books() и другие fetch_* также используют логин, а при его отсутствии пытаются разрешить числовой ID своего аккаунта. Методы get_book* принимают UUID книги.

get_my_library и get_my_bookshelves используют page и per_page. Для библиотеки значения по умолчанию — page=1, per_page=20; размер страницы должен быть от 1 до 100. Чтобы получить остальные страницы, меняйте page. Совместимый вызов get_my_library(limit=10, offset=15) возвращает нужный срез: клиент преобразует его в одну или две страницы API. limit должен быть от 1 до 100, offset — целым числом не меньше нуля; при передаче только offset используется limit=50. Смешивать limit/offset и page/per_page нельзя. Вызов без аргументов теперь использует размер страницы 20.

get_series_following() без user_id загружает профиль и запрашивает серии по его логину; токен обязателен. Если профиль уже загружен через init(), он используется повторно. Явный логин позволяет запросить серии другого пользователя.

Книги автора доступны через client.get_person_books(uuid) или person.fetch_books(). Роль по умолчанию — author; также доступны translator, narrator, illustrator и publisher. Асинхронный вариант модельного метода — await person.fetch_books_async(). Оба варианта принимают role, page, per_page. book.download_cover() и comicbook.download_cover() возвращают путь к файлу; поддерживаемые размеры — small и large. Метод fetch_impressions() у Book, Audiobook и Comicbook получает рецензии соответствующего типа контента; асинхронный вариант — fetch_impressions_async().

GraphQL-методы search, search_books, get_subscriptions и get_reading_statistics возвращают словарь ответа. Вложенные поля словаря нормализуются в snake_case. REST-методы с типом Dict также возвращают нормализованный словарь без преобразования в модель. Ошибки GraphQL могут возвращаться при HTTP 200: проверяйте result.get("errors") перед обращением к data. Ответ может одновременно содержать частичные данные и ошибки. Аргумент types принимает значения enum Type сервиса, а не имена __typename из результатов; без фильтра используйте types=None.

Модели

Модели экспортируются из yandex_book: User, Person, Image, Avatar, Book, Audiobook, Comicbook, LibraryCard, Bookshelf, Series, Label, Quote, Impression, ReadingAchievement, ReadingChallenge.

Это dataclass-модели с необязательными полями: отсутствующие в API данные обычно имеют значение None. У User есть id и uuid; у книги — title, name, display_title, cover и authors; у Image — best_url. Book.authors — список Person: для REST он заполняется из authors_objects, если поле authors пришло строкой. Исходная строка сохраняется в authors_text. Если REST не прислал объекты авторов, список пуст; текст остаётся доступным. Для GraphQL объекты берутся непосредственно из списка authors. Неизвестные поля API игнорируются, а при report_unknown_fields=True их имена попадают в лог. Модели поддерживают to_dict() и to_json(). Объекты с одинаковым идентификатором и типом считаются равными. Если идентификатор не задан полностью, разные экземпляры сохраняют свою идентичность и не сливаются при добавлении в set. Некорректные элементы списков пропускаются отдельно.

Ошибки

from yandex_book import YandexBookClient, NotFoundError, UnauthorizedError, NetworkError

with YandexBookClient("y0_...") as client:
    try:
        user = client.get_user("nonexistent")
    except NotFoundError:
        print("Пользователь не найден")
    except UnauthorizedError:
        print("Неверный токен или недостаточно прав")
    except NetworkError:
        print("Не удалось выполнить запрос")

TimedOutError наследует NetworkError. HTTP 400 вызывает BadRequestError, 401/403 — UnauthorizedError, 404 — NotFoundError, 410 — EndpointGoneError, остальные HTTP-ошибки — NetworkError. test_token() возвращает False при 401/403; ошибки сети и таймауты передаются вызывающему коду. Некорректный JSON или JSON неожиданного типа в HTTP-ответе вызывает NetworkError. EndpointGoneError наследует NetworkError и означает, что эндпоинт больше недоступен на стороне сервиса. Модельные методы проверяют наличие клиента и идентификатора обычными исключениями, в том числе при запуске python -O: неверный клиент или размер изображения вызывает InvalidOptionError, отсутствующий идентификатор — IdMissingError. DEBUG-логи клиента содержат названия вызываемых методов; полные результаты, включая приватные данные профиля, в журнал не записываются.

Недоступные достижения чтения

Старые REST-методы get_reading_achievements(year) и get_user_reading_achievements(user_id) больше не поддерживаются сервисом: API возвращает HTTP 410, библиотека вызывает EndpointGoneError с пояснением. Модели ReadingAchievement и ReadingChallenge сохранены для обработки старых данных.

Текущую статистику своего аккаунта можно получить через GraphQL:

with YandexBookClient(os.environ["YANDEX_BOOK_TOKEN"]) as client:
    result = client.get_reading_statistics()
    if result.get("errors"):
        print("Статистика недоступна")
    else:
        statistics = result["data"]["user"]["loyalty"]["statistics"]
        print(statistics)

Этот ответ содержит days_per_month, streak, streak_record, today_time. Он имеет другой формат и не заменяет годовые достижения или статистику произвольного другого пользователя.

Миграция с 0.1.x

В версии 2 статические методы моделей заменены методами клиента: User.get(id) → client.get_user(id), User.list_books(id) → client.get_user_books(id), Book.get(uuid) → client.get_book(uuid). Данные теперь представлены dataclass-моделями вместо Pydantic.

Разработка

Установите зависимости разработки и асинхронного клиента:

python -m pip install -e ".[dev,async]"

Дополнение dev включает build, необходимый для сборки:

python -m pytest
python generate_async_version.py
python -m build

client_async.py генерируется из client.py преобразованием AST Python. Изменения интерфейса вносятся в синхронный клиент; генератор добавляет await в вызовы HTTP-слоя и других методов клиента. Тест проверяет соответствие сгенерированного файла исходнику. HTTP-слой request_async.py поддерживается отдельно. Тесты моделей и клиентов используют локальный HTTP-сервер и не требуют токена Яндекса.

Лицензия

MIT

Metadata

Release files for yandex-book-api 2.0.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for yandex-book-api 2.0.2
File Size Uploaded
yandex_book_api-2.0.2.tar.gz 60.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for yandex-book-api 2.0.2
File Interpreter ABI Platform
yandex_book_api-2.0.2-py3-none-any.whl Python 3 none any Details

Total release size: 111.1 kB

Release files / yandex_book_api-2.0.2.tar.gz

Download URL yandex_book_api-2.0.2.tar.gz
Size 60.0 kB
Tags Source
SHA-256 checksum
How to use checksums
532991156f36c2be29dc63553fdd12856753ff4b6858bcd676df946fd049d30d
BLAKE2b-256 checksum
How to use checksums
3861ffc80a848521192a6d8ec67af8b85ed156518fe32ef87195d3b93571cd05
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Release files / yandex_book_api-2.0.2-py3-none-any.whl

Download URL yandex_book_api-2.0.2-py3-none-any.whl
Size 51.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c25ce1e054a61144f60ea4e1b771c5ea62776a031efc955862c1a67542349cb3
BLAKE2b-256 checksum
How to use checksums
3d502a971f449dff0314dd437daf33f276479146de000817e9c20b8826fc5000
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Release history Release notifications | RSS feed

This release

2.0.2 This release

2 release files

2.0.1

2 release files

2.0.0

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page