Skip to main content

gdzapi

Universal asynchronous and synchronous Python client for 9 GDZ providers with declarative engine and Pydantic v2 validation.

PyPI version Python Versions License: MIT Tests

Quick Start · 9 Providers · Features · Usage Guide · Architecture · License


Why gdzapi

Most school scraping tools are fragmented across dozens of fragile files, lack asynchronous capability, crash on repeated awaits, or fail to handle modern SPA/lazy-loading structures.

gdzapi unifies 9 major school solution portals under a single, declarative architecture. Instead of maintaining separate scrapers for each website, all providers are driven by a single engine with non-blocking initialization, strict timeouts, protocol normalization, and Pydantic v2 models.


Supported Providers

Provider Alias Sync Method Async Method Content Type Status
GDZ.ru "gdz" Client.gdz() AsyncClient.gdz() Images Stable
Euroki.org "euroki" Client.euroki() AsyncClient.euroki() Images (lazy) Stable
MegaResheba.ru "megaresheba" Client.megaresheba() AsyncClient.megaresheba() Images Stable
GDZ-Raketa.ru "raketa" Client.raketa() AsyncClient.raketa() Text, MathJax & Images Stable
Reshak.ru "reshak" Client.reshak() AsyncClient.reshak() Images Stable
Pomogalka.me "pomogalka" Client.pomogalka() AsyncClient.pomogalka() Images Stable
Resh.Skysmart.ru "skysmart" Client.skysmart() AsyncClient.skysmart() Steps & Images Stable (SSR)
GDZ-Putina.fun "putina" Client.putina() AsyncClient.putina() High-res Images (JSON) Stable
GDZ.ltd "ltd" Client.ltd() AsyncClient.ltd() High-res Images Stable

Features

  • Single Unified Engine: Zero code duplication. Switch providers with a string: Client("reshak") or Client.reshak().
  • Dual Mode (Sync & Async): Native asynchronous aiohttp engine alongside a robust synchronous requests client.
  • Rich Solution Models: Solution models support image_src, text, and html for sites with formulaic or written step-by-step explanations.
  • Safe Lazy Navigation: Await properties (subject.books, book.pages, page.solutions) as many times as you like without cannot reuse already awaited coroutine crashes.
  • Pydantic v2 Models: Data transfer objects (Class, Subject, Book, Page, Solution) with strict typing.
  • Fast Search: Server-side instant search on supported providers (e.g. Euroki) and concurrent catalog scanning on others.
  • Resilient Networking: Explicit 15s default timeouts, modern User-Agent handling (including SSR emulation for SPAs), and protocol-relative URL normalization (//...https://...).

Installation

pip install gdzapi --upgrade

From source for development:

git clone https://github.com/maybewewill/gdzAPI.git
cd gdzAPI
pip install -e ".[dev]"

Quick Start

Asynchronous (Recommended)

import asyncio
from gdzapi import AsyncClient, Provider

async def main():
    # Connect to any provider: "gdz", "reshak", "raketa", "euroki", etc.
    async with AsyncClient(Provider.RESHAK, timeout=15) as client:
        subjects = await client.get_subjects()
        math = next(s for s in subjects if "математика" in s.name.lower())

        books = await math.books
        print(f"Book: {books[0].name}")

        pages = await books[0].pages
        if pages:
            solutions = await pages[0].solutions
            print(f"Solution image: {solutions[0].image_src}")

if __name__ == "__main__":
    asyncio.run(main())

Synchronous

from gdzapi import Client

# Using provider factory method
with Client.pomogalka(timeout=15) as client:
    for cls in client.classes:
        if cls.id == 5:
            print(f"Grade: {cls.name}")
            for subj in cls.subjects:
                books = subj.books
                if books:
                    print(f"Book: {books[0].name}")
                    pages = books[0].pages
                    if pages:
                        print(f"Page 1 solution: {pages[0].solutions[0].image_src}")
                break
            break

Usage Guide

1. GDZ-Raketa (Text & Math Solutions)

gdz-raketa.ru provides full text answers with formulas in addition to images:

from gdzapi import Client

client = Client.raketa()
classes = client.classes
book = classes[4].subjects[0].books[0]  # 5th grade, 1st subject, 1st book

page = book.pages[0]
solution = page.solutions[0]

print("Text explanation:", solution.text)
if solution.image_src:
    print("Illustration:", solution.image_src)

2. Reshak.ru

from gdzapi import Client

client = Client.reshak()
subjects = client.subjects

for subj in subjects:
    if "математика" in subj.name.lower():
        for book in subj.books:
            print(f"{book.name} -> {book.url}")
            pages = book.pages
            if pages:
                print(f"First exercise solution: {pages[0].solutions[0].image_src}")
            break
        break

3. Euroki (Fast Search)

from gdzapi import Client

client = Client.euroki()
books = client.search_books("Геометрия 8 класс")

for book in books:
    print(f"Found: {book.name}")
    pages = book.pages
    if pages:
        solutions = pages[0].solutions
        print(f"Image: {solutions[0].image_src}")
    break

4. Resh.Skysmart.ru

from gdzapi import Client

client = Client.skysmart()
classes = client.classes
print(f"Loaded {len(classes)} grades from Skysmart")

5. GDZ-Putina.fun & GDZ.ltd

from gdzapi import Client

# GDZ-Putina (JSON API integration)
client_putina = Client.putina()
books = client_putina.classes[0].subjects[0].books
if books:
    page = books[0].pages[0]
    print(f"Putina solution: {page.solutions[0].image_src}")

# GDZ.ltd
client_ltd = Client.ltd()
math_books = client_ltd.classes[0].subjects[0].books
if math_books:
    print(f"LTD book: {math_books[0].name}")
    print(f"LTD solution: {math_books[0].pages[0].solutions[0].image_src}")

6. Error Handling

from gdzapi import Client, NetworkError, ParsingError

client = Client.gdz(timeout=10)

try:
    books = client.get_books("/non-existent-subject")
except NetworkError as e:
    print(f"Connection or HTTP status error for {e.url}: {e}")
except ParsingError as e:
    print(f"Parsing error: {e}")

Architecture

gdzapi/
├── __init__.py      # Unified public API and provider factory shortcuts
├── client.py        # Single Sync & Async execution engine (Client, AsyncClient)
├── providers.py     # Declarative registry defining all 9 providers
├── models.py        # Pydantic v2 models (Class, Subject, Book, Page, Solution, AwaitableList)
├── exceptions.py    # GDZError, NetworkError, ParsingError, NotFoundError
└── utils.py         # URL normalization, DOM parsers, HTTP headers

Adding a New Provider in 20 Lines

Because gdzapi uses a declarative provider engine, you do not need to create new files or rewrite sync/async boilerplate to add an 8th provider. Simply define a ProviderSpec in gdzapi/providers.py:

MY_SPEC = ProviderSpec(
    name="myprovider",
    base_url="https://example.com",
    display_name="My Provider",
    extract_subjects=_my_subjects,
    extract_books=_my_books,
    extract_pages=_my_pages,
    extract_solutions=_my_solutions,
)

The unified Client and AsyncClient automatically provide sync, async, caching, and lazy navigation support out of the box.


Testing

The test suite includes 21 isolated offline unit tests and 8 live integration tests across all 7 providers:

# Run unit tests (offline, instantaneous)
pytest -v -m "not live"

# Run all tests including live network requests
pytest -v

License

gdzapi is distributed under the terms of the MIT license.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gdzapi-1.1.0.tar.gz (24.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gdzapi-1.1.0-py3-none-any.whl (17.0 kB view details)

Uploaded Python 3

File details

Details for the file gdzapi-1.1.0.tar.gz.

File metadata

  • Download URL: gdzapi-1.1.0.tar.gz
  • Upload date:
  • Size: 24.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.6

File hashes

Hashes for gdzapi-1.1.0.tar.gz
Algorithm Hash digest
SHA256 485d3b14dbe58c65c1fb880526a02d13ae597c5443ac5febe5c078c5258c2115
MD5 2916097f0bec1e3db5ca8603a4d2f19c
BLAKE2b-256 9ae7e0d80ddb9021271c241d94250f1342e1c263ce39facefbf8861a2e017d9e

See more details on using hashes here.

File details

Details for the file gdzapi-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: gdzapi-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 17.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.6

File hashes

Hashes for gdzapi-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 125e7f0024dc4d38b6b01906069aa58cada0782ebf1df780348908ddd308462c
MD5 ca0d59affa69ef1a7b99357c6beb7b14
BLAKE2b-256 87a562a2350589fc29cf818513c74991f6ec6794afbea75fef5bffa91fc9e48e

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

1.1.0 This release

2 files

1.0.0

2 files

0.2.0

1 file

0.1.14

1 file

0.1.13

1 file

0.1.11

1 file

0.1.9

1 file

0.1.8

1 file

0.1.7

1 file

0.1.6

1 file

0.1.5

1 file

0.1.4

1 file

0.1.2

2 files

0.1.1

2 files

0.1.0

2 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