Всем добрый день!
В этом году я являюсь выпускником 11 класса и, соответственно, человеком, который сдает ЕГЭ. Результаты экзаменов обычно приходят не раньше, чем через неделю. При этом их можно отслеживать как минимум на 3 ресурсах: Госуслуги, Checkege (единый портал) и на сайтах региональных центров обработки информации — РЦОИ. Тенденция последних лет показывает, что раньше всего результаты появляются на региональных ресурсах.
Поэтому, находясь в томительном ожидании, я решил проанализировать сайт РЦОИ Пермского края. Важно отметить, что в каждом регионе эти сайты различаются, поэтому универсального рецепта здесь нет, никакой документации для разработчиков или публичного API тем более.
Для получения результатов экзамена необходимо знать только серию и номер паспорта. После их ввода результаты представляются в виде обезличенной таблицы.
Порадовало отсутствие капч и каких‑либо антифрод систем на сайте, это безусловно облегчит задачу.
Приступим
Сначала я нашел PHP‑скрипт, которому передаются номер и серия паспорта экзаменуемого, но при попытке просто передать данные была получена ошибка «Сессия не создана». Оказывается, страница ввода паспортных данных генерирует некоторый «rhash», который необходимо передать в параметрах скрипту, при этом каждый такой сгенерированный хеш можно использовать только один раз, иначе мы рискуем получить ошибку «Сессия на активна».
Так как разрабатывать бота я решил на Python, то запросы тестировались сразу с использованием библиотеки requests.
>>> params = {'rhash': '581db7b0f8dd2ed7482c7674b49f1bea5ff6d806978f', 'ds':'', 'dn':''}
>>> r = requests.get('https://kraioko.perm.ru/utils/results/loadstudentresults.php', params=params)
>>> r.text
<table width=100%>\r\n <tr bgcolor=linen class=headline>\r\n <td>Предмет\r\n <td>Тестовый балл\t\t\t\r\n <td>Результат\r\n <td>Год<tr bgcolor=white><td><a id='id5CD1D809-54C4-4CBF-8CEF-ADE985B98146'>Русский язык</a><td>93\r\n <td>Экзамен сдан\r\n <td>2023
длинный и малочитамемый код таблицы
Всё, необходимые данные были получены. Далее я выполнил парсинг с помощью классических инструментов — BeautifulSoup4 и lxml. В результате таблица была упакована в такой удобочитаемый вид:
[['Русский язык', '93', 'Экзамен сдан', '2023'], ['Математика', '90', 'Экзамен сдан', '2024'], ['Информатика', '93', 'Экзамен сдан', '2024']]
Самая нетривиальная задача этого проекта была решена, теперь осталось создать бота с использованием aiogram и добавить базу данных sqlite3 для хранения пользовательских данных.
Телеграм Бот
Сразу после запуска бота пользователю необходимо сохранить паспортные данные, затем получение результатов сводится к вводу одной команды /check
. Для сохранения конфиденциальности, несмотря на то, что сохраняются только 10 цифр из паспорта, Telegram ID пользователя хешируется и добавляется в таблицу БД именно в таком виде. При запросе результатов происходит хеширование ID пользователя и запрос паспортных данных на основании этого хеш‑значения.
Получение результатов теперь доступно, оставалось самое главное — мониторинг результатов и уведомления об их изменениях на сайте. Ради этого пришлось пожертвовать конфиденциальностью, т.к. необходимо точное сопоставление «Пользователь и его Chat ID — Паспортные данные» для того, чтобы отправить изменения в случае их появления.
Чтобы не сохранять в БД полный список результатов для каждого пользователя, я решил хешировать эти данные с помощью SHA-256 и хранить это значение в таблице (изначально я использовал длину полученной таблицы, как маркер для изменений, но стало очевидно, что баллы по предметам могут быть изменены без добавления новых строк).
Затем я написал асинхронную функцию, которая получает результаты, хеширует их и сверяет с сохраненным значением в БД. При изменениях хеш перезаписывается, а пользователю приходит уведомление. Функция выполняется раз в 10 минут, но это значение может быть изменено администратором бота без перезапуска (были реализованы несколько админских команд).
Развертывание и интеграция
Далее я создал Dockerfile и использовал имеющийся у меня шаблон пайплайна Jenkins, чтобы развернуть это все на небольшом домашнем сервере с локальным инстансом Gitea. Конечно, был адаптирован не весь функционал ресурса (например, возможность просмотра разбалловки по заданиям конкретного экзамена), но достаточно того, что пользователи теперь могут получать уведомления о результатах в числе первых.
Основной функционал бота (в том числе и мониторинг результатов) был реализован за одни сутки. В дальнейшем, перед публикацией, производился рефакторинг кода и разделение его по файлам :).