Как стать автором
Обновить

Технологический прорыв в онлайн-обучении или как «умные» школьники могли схитрить в пандемию

Уровень сложностиСредний

Предыстория

Все мы когда-то учились в школе - кто-то хорошо, кто-то не очень, а кто-то и вовсе плохо. Работа педагогов, которые найдут шпаргалки там, где их нет, один на один могла отразить настоящий уровень подготовки ученика, а оттуда и тройки, а то и двойки...но пришла ковидная пора весной 2020 года, и школы РФ массово стали применять образовательные сервисы для организации дистанционного обучения, что сильно повлияло на успеваемость школьников в "лучшую" сторону. Так было и в моей школе, где масса учителей отдали свой выбор в пользу Российской Электронной Школы (РЭШ).

Поначалу, как и все мои одноклассники, я исправно выполнял задания, но давайте будем честны - в какой-то момент времени мне это стало докучать, ибо резкий переход к иной форме обучения был достаточно болезненным, а монотонное выполнение заданий не добавляло интереса к учебе. Гугл особо не помогал в поисках ответов на задания, а предприимчивые люди стали предлагать ответы за деньги, прикидываясь "администрацией" РЭШ. Однако в один прекрасный день я случайно нашел сервис DZ-Helper, который заинтересовал возможностью просмотра ответов на задания, что навело на мысль, что вероятно я нашел медь, а до золота придется покопаться поглубже..

Поиски "золота"

К каждому уроку на сайте прилагаются тренировочные задания и контрольные задания B1 и B2. После выполнения тренировочных заданий, присутствует возможность просмотра ответов, чем мы и воспользуемся:

При нажатии кнопки, как ни странно, происходит запрос (GET https://resh.edu.ru/tests/{task_id}/get-answers), на что возвращается JSON-массив с непонятными "кракозябрами" - идентификаторами полей и значений:

Отправим задания на проверку (POST https://resh.edu.ru/subject/lesson/{lesson_id}/train/result/):

Содержимое массива как-то сильно похоже на то, что мы получили ранее, но имеет несколько иной вид.

Воспользуемся магией программирования и попробуем получить положительную оценку. Я написал небольшой скрипт на Python, который получает ответы и отправляет их в корректном виде:

import requests
import re
import json

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 Edg/129.0.0.0',
    'Cookie': 'Сюда свои куки',
    'X-Requested-With': 'XMLHttpRequest'
}

def tasks_type(tasks_type: int = 1):
    if tasks_type == 2:
        return 'control/1/'
    elif tasks_type == 3:
        return 'control/2/'
    else:
        return 'train/'

def get_lesson_tasks(id: int, tasksType: int = 1) -> list[int]:
    url = 'https://resh.edu.ru/subject/lesson/' + str(id) + '/' + tasks_type(tasksType)
    response = requests.get(url, headers=headers).content.decode('utf-8')

    tasks = re.finditer(r"data-test-id=\"(\d+)\"", response, re.UNICODE)
    return [int(task.group(1)) for task in tasks]

def get_task_answer(id: int) -> dict[str: bool | list[str]]:
    url = 'https://resh.edu.ru/tests/' + str(id) + '/get-answers'

    response = requests.get(url, headers=headers).json()

    if response == []:
        return {'RESPONSE1': True}

    out = dict()
    for key in response:
        if len(response[key]) > 1:
            out[key] = [answer['value'] for answer in response[key]]
        else:
            out[key] = response[key][0]['value']

    return out

def get_lesson_answers(id: int, tasksType: int = 1) -> dict[str: dict[str: bool | list[str]]]:
    tasks = get_lesson_tasks(id, tasksType)

    out = dict()
    for task_id in tasks:
        out[str(task_id)] = get_task_answer(task_id)

    return out

def solve_lesson(id: int, tasksType: int = 1) -> bool:
    answers = get_lesson_answers(id, tasksType)
    url = 'https://resh.edu.ru/subject/lesson/' + str(id) + '/' + tasks_type(tasksType) + 'result/'

    success = False
    while not success:
        try:
            response = requests.post(url, headers=headers, data={'answers': json.dumps(answers)}).json()
            success = True
        except requests.exceptions.JSONDecodeError:
            pass

    try:
        if response['success']:
            return True
    except KeyError:
        pass

    return False

Вдаваться в подробности не буду - кому нужно, тот разберется сам.

Не забываем подставить куки, чтобы авторизоваться, и вызываем функцию solve_lesson(), передавая два аргумента:

  1. ID - Идентификатор урока из URI

  2. Что решаем (1 - тренировочные задания; 2 - контрольные задания B1; 3 - контрольные задания B2)

ID урока
ID урока

Заключение

Не торопясь, попивая колу и закусывая чипсами, школьник, который хоть как-то овладел питоном и реверс-инжинирингом, может решить проблему с невыполненными/выполненными неправильно заданиями раз и навсегда, что я и сделал в школьные годы xD

Возможно когда-нибудь разработчики РЭШа одумаются и придумают какой-нибудь способ защиты от шаловливых ручек, а пока что есть то, что есть..

Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.