Pull to refresh

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

Level of difficultyMedium

Предыстория

Все мы когда-то учились в школе - кто-то хорошо, кто-то не очень, а кто-то и вовсе плохо. Работа педагогов, которые найдут шпаргалки там, где их нет, один на один могла отразить настоящий уровень подготовки ученика, а оттуда и тройки, а то и двойки...но пришла ковидная пора весной 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

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

Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.