Metadata-Version: 2.4
Name: sdamgia-client
Version: 0.1.0
Summary: Self-validating client for sdamgia.ru (РешуОГЭ / РешуЕГЭ): discovery + correct content parsing for all subjects.
Author: Tommy
License: MIT
Keywords: sdamgia,reshuoge,oge,ege,math,exam,scraper
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: httpx>=0.24
Requires-Dist: beautifulsoup4>=4.11
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Dynamic: license-file

# sdamgia-client

Клиент для [sdamgia.ru](https://sdamgia.ru) («РешуОГЭ» / «РешуЕГЭ») с **корректным и самопроверяющимся разбором контента**. Работает со всеми предметами и обоими экзаменами.

[English](README.en.md) · MIT License

## Зачем это нужно

Собирать реальный экзаменационный контент с sdamgia.ru не так просто, как кажется. Подводные камни:

- У прикладных задач (например, математика, задания 1–5) **два блока условия**: общий сценарий и вопрос конкретного задания. Наивный парсер принимает второй блок за *решение* — вопрос попадает не в то поле, а настоящее решение теряется.
- **Никакой валидации** в типичных решениях — битые разборы возвращаются молча.
- Таблицы, некорректная вложенность тегов `<p>` и относительные адреса рисунков легко искажаются.

Эта библиотека исправляет парсер, проверяет каждый разбор и содержит замороженный самотест: если sdamgia изменит HTML, тест громко сломается, а не молча испортит банк заданий.

## Установка

```bash
pip install sdamgia-client
```

## Использование

```python
from sdamgia_client import SdamgiaClient, Subject, ExamType

client = SdamgiaClient(rps=2.5)

# Контент — корректный и проверенный
p = client.get_problem("408182", Subject.MATH, ExamType.OGE)
p.condition, p.scenario, p.answer, p.solution
p.images            # рисунки и формулы с типом (figure/formula)
p.solution_images   # изображения решения (шаги, чертежи)

# Навигация
cat = client.get_catalog(Subject.MATH, ExamType.OGE)   # темы 1:1 к заданиям экзамена
ids = client.get_category_problems("15", Subject.MATH, ExamType.OGE)
vs  = client.list_variants(Subject.MATH, ExamType.OGE) # реальные варианты прошлых лет
var = client.get_variant(vs[0].id, Subject.MATH, ExamType.OGE)
```

Работают все предметы (`Subject.RUS`, `Subject.PHYS`, …) для обоих экзаменов (`ExamType.OGE`, `ExamType.EGE`) — адрес сайта строится из значений перечислений.

## Валидация

`get_problem()` проверяет каждый разбор и при плохом контенте бросает `SdamgiaValidationError` (пустое или подозрительно длинное условие, отсутствующий ответ для части 1, нечисловой номер задания, относительные адреса изображений, рисунки в HTML, не попавшие в список). Битые задачи не возвращаются молча.

У старых задач из банка ФИПИ на странице нет пометки «Тип N»; передайте `topic_hint`, чтобы унаследовать номер задания:

```python
p = client.get_problem("137272", Subject.MATH, ExamType.OGE, topic_hint="2")
```

## Самотест

```bash
sdamgia-selftest
# или
python -m sdamgia_client.selftest
```

Загружает замороженный набор заведомо корректных задач и проверяет инварианты (в том числе то, что у членов одного сценария текст сценария совпадает байт-в-байт и что таблицы превращаются в строки). Запускайте перед большим обходом.

## Вежливость к сайту

- Ограничение частоты запросов (по умолчанию 2.5 rps), повторы с экспоненциальной паузой, 429 учитывает `Retry-After`, при отвале сети запрос быстро падает по таймауту, а не виснет навсегда.
- Ограничитель потокобезопасен; для параллельного обхода создавайте по одному клиенту на поток (`httpx.Client` не потокобезопасен).

## Примечания

- Контент берётся с публичного сайта (robots.txt без ограничений). Парсеры навигации адаптированы из MIT-библиотеки `oge-sdamgia-api` (форк princeofscale); парсер контента и валидация написаны с нуля.

## Лицензия

MIT
