SdamGIA Api
SdamGIA Api – Python модуль для взаимодействия с образовательным порталом СДАМ ГИА
Структура СдамГИА
Чтобы было проще понять, как устроена база заданий СдамГИА, предлагаю воспользоваться следующей схемой:
СдамГИА
└── Предмет (subject)
├── Каталог заданий (catalog)
│ └── Задание (topic)
│ └── Категория (category)
│ └── Задача (problem)
└── Тест (test)
└── Задача (problem)
У каждой задачи, категории или теста есть свой идентификатор.
Задания тоже имеют номера, которые в свою очередь могут иметь такие значения как «Д1» или «C4». Этим они отличаются от идентификаторов.
Установка
$ pip3 install sdamgia-api
Установка зависимостей
Для поиска задач по тексту на изображении необходимо установить pytesseract:
$ pip3 install pytesseract
А также Tesseract-OCR
Обратите внимание, что для корректной работы нужен русский языковой пакет
Использование
Инициализация
from sdamgia import SdamGIA sdamgia = SdamGIA()
Поиск задачи по ее идентификатору
subject = 'math' id = '1001' sdamgia.get_problem_by_id(subject, id)
{ 'id': '1001', 'topic': '4', 'condition': { 'text': 'На экзамен вынесено 60 вопросов, Андрей не выучил 3 из них. Найдите вероятность того, что ему попадется выученный вопрос.', 'images': [] }, 'solution': { 'text': 'Решение.Андрей выучил 60xa0–xa03xa0=xa057 вопросов. Поэтому вероятность того, что на экзамене ему попадется выученный вопрос равнаxa0Ответ: 0,95.', 'images': ['https://ege.sdamgia.ru/formula/svg/9f/9fbf55ab44a507fb47ba8a2666cd7644.svg'] }, 'answer': '0,95', 'analogs': ['1001', '1002', '1003', '1004', '1005', '1006', '1007', '1008', '1009', '1010'], 'url': 'https://math-ege.sdamgia.ru/problem?id=1001' }
Можно сгенерировать задачу в виде изображения:
path_to_img = '/imgs/problem.png' sdamgia.get_problem_by_id(subject, id, path_to_img=path_to_img)
Поиск задач по запросу
subject = 'math' request = 'Найдите количество' sdamgia.search(subject, request)
['6407', '8795', '8799', '27501', '519508', '519534', '525371', '512436', '6401', '6421', '6427', '7321', '7325', '7801', '7803', '7807', '7809', '8037', '8039', '8045']
Поиск теста по его идентификатору
subject = 'math' id = '1770' sdamgia.get_test_by_id(subject, id) # Возвращает список задач, входящих в тест
['77345', '28765', '77374', '27903', '26675', '27700', '77411', '27506', '27132', '28008', '26703', '99592']
Поиск категории по ее идентификатору
subject = 'math' id = '1' sdamgia.get_category_by_id(subject, id) # Возвращает список задач, входящих в категорию
['77334', '323512', '501201', '509077', '509106']
Получение каталога
subject = 'math' sdamgia.get_catalog(subject)
[ { 'topic_id': '1', 'topic_name': 'Простейшие текстовые задачи', 'categories': [ {'category_id': '174', 'category_name': 'Вычисления'}, {'category_id': '1', 'category_name': 'Округление с недостатком'}, {'category_id': '2', 'category_name': 'Округление с избытком'}, {'category_id': '249', 'category_name': 'Проценты'}, {'category_id': '5', 'category_name': 'Проценты и округление'} ] }, { ... } ]
Генерация теста
По умолчанию генерируется тест, включающий по одной задаче из каждого задания предмета.
Так же можно вручную указать одинаковое количество задач для каждого из заданий: {‘full’: <кол-во задач>}
Указать определенные задания с определенным количеством задач для каждого: {<номер задания>: <кол-во задач>, … }
subject = 'math' problems = {1: 1, 2: 2, 3: 4} sdamgia.generate_test(subject, problems) # Возвращает идентификатор сгенерированного теста
Обратите внимание, что в этом случае идентификатор задания — только науральное число. Т.е. если после задания 15 идет задание Д1, оно должно будет записываться как 16 задание.
Генерация pdf-версии теста
sdamgia.generate_pdf('math', '38299510', pdf='h')
https://math-ege.sdamgia.ru/pdf/1fe7d7d8408f8d5195fabfd8ab393d63.pdf
Список параметров:
subject: Наименование предмета
testid: Идентифигатор теста
solution: Пояснение
nums: № заданий
answers: Ответы
key: Ключ
crit: Критерии
instruction: Инструкция
col: Нижний колонтитул
pdf: Версия генерируемого pdf документа
По умолчанию генерируется стандартная вертикальная версия
h - горизонтальная версия
z - версия с крупным шрифтом
m - версия с большим полем
Поиск задач по изображению beta
С помощью sdamgia-api вы можете искать задачи по тексту на изображении. Например, на фотографии распечатки.
Для начала, необходимо указать путь к исполняемому файлу Tesseract-OCR:
sdamgia.tesseract_src = "C:/Program Files/Tesseract-OCR/tesseract.exe"
Теперь мы можем запустить поиск:
sdamgia.search_by_img('rus', 'Image.jpg') # Возвращает список найденных задач
['12629', '14062', '2846', '2836', '2837', '2838', '2839', '2845', '2847', '7776', '10242', '874', '864', '865', '866', '867', '873', '2359', '456', '446', '447', '448', '449', '455', '2348', '7815', '691', '863', '14426', '7867', '1262', '1889', '6716', '6706', '6707', '6708', '6709', '6715', '6717', '8899', '8895', '8896', '8897', '8898', '8900', '4194', '4184', '4185', '4186', '4187', '4193', '4195', '30', '28', '29', '31', '37', '38', '2337', '676', '674', '675', '677', '683', '684', '2168', '1094', '1092', '1093', '1095', '1101', '1102', '2365', '6893', '6891', '6892', '6894', '6900', '6901', '6902', '599', '598', '600', '601', '607', '608', '2352', '1710', '1700', '1701', '1702', '1703', '1709', '2381', '3600', '3599', '3601', '3602', '3608', '3609', '3610', '8327', '8323', '8324', '8325', '8326', '8328', '950', '940', '941', '942', '943', '949', '2361', '11087', '11065', '1304', '1299', '1342', '1337', '1474', '1472', '1473', '1475', '1481', '1482', '2375', '105', '104', '106', '107', '113', '114', '2339', '181', '180', '182', '183', '189', '190', '2341', '257', '256', '258', '259', '265', '266', '1321', '2343', '333', '332', '334', '335', '341', '342', '2345', '380', '370', '371', '372', '373', '379', '2346', '532', '522', '523', '524', '525', '531', '2350', '656', '652', '759', '750', '751', '752', '753', '760', '2356', '789', '788', '790', '791', '797', '798', '2357', '844', '842', '988', '978', '979', '980', '981', '987', '2362', '997', '995', '1026', '1016', '1017', '1018', '1019', '1025', '2363', '1254', '1244', '1245', '1246', '1247', '1253', '2369', '1292', '1282', '1283', '1284', '1285', '1291', '2370', '7568']
Поиск может занять продолжительное время в зависимости от объема текста и количества найденных задач
SdamGIA Api – Python модуль для взаимодействия с образовательным порталом СДАМ ГИА
Структура СдамГИА
Чтобы было проще понять, как устроена база заданий СдамГИА, предлагаю воспользоваться следующей схемой:
СдамГИА
└── Предмет (subject)
├── Каталог заданий (catalog)
│ └── Задание (topic)
│ └── Категория (category)
│ └── Задача (problem)
└── Тест (test)
└── Задача (problem)
У каждой задачи, категории или теста есть свой идентификатор.
Задания тоже имеют номера, которые в свою очередь могут иметь такие значения как «Д1» или «C4». Этим они отличаются от идентификаторов.
Установка
$ pip3 install sdamgia-api
Установка зависимостей
Для поиска задач по тексту на изображении необходимо установить pytesseract:
$ pip3 install pytesseract
А также Tesseract-OCR
Обратите внимание, что для корректной работы нужен русский языковой пакет
Использование
Инициализация
from sdamgia import SdamGIA sdamgia = SdamGIA()
Поиск задачи по ее идентификатору
subject = 'math' id = '1001' sdamgia.get_problem_by_id(subject, id)
{ 'id': '1001', 'topic': '4', 'condition': { 'text': 'На экзамен вынесено 60 вопросов, Андрей не выучил 3 из них. Найдите вероятность того, что ему попадется выученный вопрос.', 'images': [] }, 'solution': { 'text': 'Решение.Андрей выучил 60xa0–xa03xa0=xa057 вопросов. Поэтому вероятность того, что на экзамене ему попадется выученный вопрос равнаxa0Ответ: 0,95.', 'images': ['https://ege.sdamgia.ru/formula/svg/9f/9fbf55ab44a507fb47ba8a2666cd7644.svg'] }, 'answer': '0,95', 'analogs': ['1001', '1002', '1003', '1004', '1005', '1006', '1007', '1008', '1009', '1010'], 'url': 'https://math-ege.sdamgia.ru/problem?id=1001' }
Можно сгенерировать задачу в виде изображения:
path_to_img = '/imgs/problem.png' sdamgia.get_problem_by_id(subject, id, path_to_img=path_to_img)
Поиск задач по запросу
subject = 'math' request = 'Найдите количество' sdamgia.search(subject, request)
['6407', '8795', '8799', '27501', '519508', '519534', '525371', '512436', '6401', '6421', '6427', '7321', '7325', '7801', '7803', '7807', '7809', '8037', '8039', '8045']
Поиск теста по его идентификатору
subject = 'math' id = '1770' sdamgia.get_test_by_id(subject, id) # Возвращает список задач, входящих в тест
['77345', '28765', '77374', '27903', '26675', '27700', '77411', '27506', '27132', '28008', '26703', '99592']
Поиск категории по ее идентификатору
subject = 'math' id = '1' sdamgia.get_category_by_id(subject, id) # Возвращает список задач, входящих в категорию
['77334', '323512', '501201', '509077', '509106']
Получение каталога
subject = 'math' sdamgia.get_catalog(subject)
[ { 'topic_id': '1', 'topic_name': 'Простейшие текстовые задачи', 'categories': [ {'category_id': '174', 'category_name': 'Вычисления'}, {'category_id': '1', 'category_name': 'Округление с недостатком'}, {'category_id': '2', 'category_name': 'Округление с избытком'}, {'category_id': '249', 'category_name': 'Проценты'}, {'category_id': '5', 'category_name': 'Проценты и округление'} ] }, { ... } ]
Генерация теста
По умолчанию генерируется тест, включающий по одной задаче из каждого задания предмета.
Так же можно вручную указать одинаковое количество задач для каждого из заданий: {‘full’: <кол-во задач>}
Указать определенные задания с определенным количеством задач для каждого: {<номер задания>: <кол-во задач>, … }
subject = 'math' problems = {1: 1, 2: 2, 3: 4} sdamgia.generate_test(subject, problems) # Возвращает идентификатор сгенерированного теста
38299510
Обратите внимание, что в этом случае идентификатор задания — только науральное число. Т.е. если после задания 15 идет задание Д1, оно должно будет записываться как 16 задание.
Генерация pdf-версии теста
sdamgia.generate_pdf('math', '38299510', pdf='h')
https://math-ege.sdamgia.ru/pdf/1fe7d7d8408f8d5195fabfd8ab393d63.pdf
Список параметров:
subject: Наименование предмета
testid: Идентифигатор теста
solution: Пояснение
nums: № заданий
answers: Ответы
key: Ключ
crit: Критерии
instruction: Инструкция
col: Нижний колонтитул
pdf: Версия генерируемого pdf документа
По умолчанию генерируется стандартная вертикальная версия
h - горизонтальная версия
z - версия с крупным шрифтом
m - версия с большим полем
Поиск задач по изображению beta
С помощью sdamgia-api вы можете искать задачи по тексту на изображении. Например, на фотографии распечатки.
Для начала, необходимо указать путь к исполняемому файлу Tesseract-OCR:
sdamgia.tesseract_src = "C:/Program Files/Tesseract-OCR/tesseract.exe"
Теперь мы можем запустить поиск:
sdamgia.search_by_img('rus', 'Image.jpg') # Возвращает список найденных задач
['12629', '14062', '2846', '2836', '2837', '2838', '2839', '2845', '2847', '7776', '10242', '874', '864', '865', '866', '867', '873', '2359', '456', '446', '447', '448', '449', '455', '2348', '7815', '691', '863', '14426', '7867', '1262', '1889', '6716', '6706', '6707', '6708', '6709', '6715', '6717', '8899', '8895', '8896', '8897', '8898', '8900', '4194', '4184', '4185', '4186', '4187', '4193', '4195', '30', '28', '29', '31', '37', '38', '2337', '676', '674', '675', '677', '683', '684', '2168', '1094', '1092', '1093', '1095', '1101', '1102', '2365', '6893', '6891', '6892', '6894', '6900', '6901', '6902', '599', '598', '600', '601', '607', '608', '2352', '1710', '1700', '1701', '1702', '1703', '1709', '2381', '3600', '3599', '3601', '3602', '3608', '3609', '3610', '8327', '8323', '8324', '8325', '8326', '8328', '950', '940', '941', '942', '943', '949', '2361', '11087', '11065', '1304', '1299', '1342', '1337', '1474', '1472', '1473', '1475', '1481', '1482', '2375', '105', '104', '106', '107', '113', '114', '2339', '181', '180', '182', '183', '189', '190', '2341', '257', '256', '258', '259', '265', '266', '1321', '2343', '333', '332', '334', '335', '341', '342', '2345', '380', '370', '371', '372', '373', '379', '2346', '532', '522', '523', '524', '525', '531', '2350', '656', '652', '759', '750', '751', '752', '753', '760', '2356', '789', '788', '790', '791', '797', '798', '2357', '844', '842', '988', '978', '979', '980', '981', '987', '2362', '997', '995', '1026', '1016', '1017', '1018', '1019', '1025', '2363', '1254', '1244', '1245', '1246', '1247', '1253', '2369', '1292', '1282', '1283', '1284', '1285', '1291', '2370', '7568']
Поиск может занять продолжительное время в зависимости от объема текста и количества найденных задач
Делаем расширение для браузера, проверяющее результаты ЕГЭ +17
JavaScript, Из песочницы, Расширения для браузеров, Google Chrome
Рекомендация: подборка платных и бесплатных курсов дизайна интерьера — https://katalog-kursov.ru/
Я, как и любой другой выпускник, переживаю по поводу экзаменов. От баллов, полученных на ЕГЭ зависит слишком многое, поэтому сейчас трудно думать о чем то другом. Чтобы не обновлять сайт check.ege.edu.ru каждые две минуты, я решил написать расширение, которое будет делать это за меня, а заодно присылать уведомления, в случае, если какой-то из экзаменов проверили.
Задача не очень сложная, но есть один неприятный момент. Сайт, на котором публикуются результаты, требует, чтобы информация о участнике, при каждом закрытии браузера, заполнялась заново. Это очень не удобно, поэтому пришлось немного по-импровизировать. Было замечено, что вся необходимая информация хранится в файлах cookie, поэтому можно просто сохранять и обновлять их когда потребуется, без необходимости вводить данные заново. Таким образом, логика работы расширения такова:
Расширения для браузера пишутся на js, оформляются с помощью html и css. В целом, разработка расширения мало чем отличается от создания сайта. Обычно любое расширение имеет следующий «скелет»:
Manifest.json
В этом файле хранится основная информация: версия, название, описание, подключаемые файлы и тд.
manifest.json
{
"manifest_version": 2,
"name": "Результаты ЕГЭ",
"description": "Расширение следит за обновлениями на сайте check.ege.edu.ru и оповещает о новых результатах",
"version": "1.0.0",
"icons": {"128": "icon.png"},
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"background": {
"scripts": ["jquery.js","background.js"], //фоновые страницы
"persistent": false
// Эта строка включает режим Event Pages, который призван улучшить производительность за счет того, что расширение будет работать только тогда, когда это необходимо. Именно поэтому в дальнейшем будет использоваться alarms вместо setInterval.
},
"permissions": [ //разрешения
"cookies",
"tabs",
"alarms",
"notifications",
"storage",
"http://check.ege.edu.ru/*",
"https://check.ege.edu.ru/*"
],
"web_accessible_resources": [
// Это необходимо для правильной работы оповещений
"icon.png"
]
}
Background.js
Код, находящийся в этом файле будет запущен сразу после открытия браузера. Именно здесь будет находится основная логика нашего расширения
background.js
chrome.alarms.create("1min", { // Повторяем код ниже каждую минуту
delayInMinutes: 1,
periodInMinutes: 1,
});
chrome.alarms.onAlarm.addListener(function(alarm) {
if (alarm.name === "1min") {
chrome.cookies.getAll({"url": 'http://check.ege.edu.ru'}, function(cookie) {
if (cookie.length){
chrome.storage.local.set({'sCookie': cookie});
// Если на сайте есть cookie файлы, то сохраняем их
checkUpdates(); // и проверяем обновления
}else{
chrome.storage.local.get(['sCookie'], function(result) {
if (!jQuery.isEmptyObject(result)){
// Если нет, то загружаем сохраненные ранее
chrome.cookies.set({
"url": 'http://check.ege.edu.ru',
"name": result["sCookie"][0]["name"],
"value": result["sCookie"][0]["value"]
}, function(){
checkUpdates(); // и тоже проверяем обновления
});
}
});
}
});
}
});
function checkUpdates(){
var myInit = {
method: 'GET',
credentials: 'include'};
fetch('http://check.ege.edu.ru/api/exam', myInit).then(r => r.text()).then(result => { // Загружаем результаты ЕГЭ
var examRes = {};
jQuery.parseJSON(result)['Result']['Exams'].forEach(function(element) {
examRes[element['Subject']] = element['TestMark'];
// Сохраняем их в массив examRes
});
chrome.storage.local.get(['examRes'], function(result) {
for (var element in result['examRes']){
if (result['examRes'][element] != examRes[element]){
showNotification(element, examRes[element]);
chrome.storage.local.set({'examRes': examRes});
// Если они не совпадают, с прошлыми данными, то
// показываем уведомление
// и сохраняем новые данные
}
}
});
})
}
function showNotification(subName, mark){
// показываем уведомление, состоящее их названия предмета и баллов
chrome.notifications.create('reminder', {
type: 'basic',
iconUrl: 'icon.png',
title: 'Новые результаты!',
message: subName + ' - ' + mark
});
}
Popup.html
В этом файле хранится разметка popup окна, которое открывается при нажатии на иконку расширения. В нашем случае, в этом окне будет отображаться небольшая таблица с результатами ЕГЭ.
popup.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Результаты ЕГЭ</title>
<script type="text/javascript" src="jquery.js"></script>
<script src="popup.js"></script>
<style>
<!-- Здесь ничего интересного -->
</style>
</head>
<body>
<table border="1" id="mainTable">
<caption><b>Ваши результаты ЕГЭ</b></caption>
<tr>
<th>Предмет</th>
<th>Тестовый балл</th>
</tr>
</table>
</body>
</html>
В заголовке мы подключили файл popup.js, который будет исполняться при каждом нажатии на иконку расширения. Вот его содержимое:
popup.js
chrome.cookies.getAll({"url": 'http://check.ege.edu.ru'}, function(cookie) {
// Смотрим, установлены ли на сайте необходимые cookie
if (cookie.length){
chrome.storage.local.set({'sCookie': cookie});
createTable();
// Если они есть, то сохраняем их и отрисовываем таблицу
}else{
chrome.storage.local.get(['sCookie'], function(result) {
// Если нет, то смотрим, нет ли у нас сохраненных ранее cookie файлов
if (!jQuery.isEmptyObject(result)){
chrome.cookies.set({
"url": 'http://check.ege.edu.ru',
"name": result["sCookie"][0]["name"],
"value": result["sCookie"][0]["value"]
}, function(){
// Если есть, то устанавливаем их и отрисовываем таблицу
createTable();
});
}else{
// А если нет, то открываем сайт check.ege.edu.ru в новой вкладке
chrome.tabs.create({url : "http://check.ege.edu.ru"});
}
});
}
});
function createTable(){
var myInit = {
method: 'GET',
credentials: 'include'};
fetch('http://check.ege.edu.ru/api/exam', myInit).then(r => r.text()).then(result => {
// Получаем результаты и парсим их
jQuery.parseJSON(result)['Result']['Exams'].forEach(function(element) {
if (element['HasResult'] == false){
// Если результата еще нет, то выводим название предмета и надпись "не проверено"
$("#mainTable").append('<tr><td>'+element['Subject']+'</td><td>Не проверено</td></tr>');
}else{
// Если есть, то выводим название предмета и баллы
$("#mainTable").append('<tr><td>'+element['Subject']+'</td><td>'+element['TestMark']+'</td></tr>');
}
});
})
}
Итого, весь код занимает менее 200 строк. Надеюсь, что это расширение пригодится не только мне. В любом случае, во время разработки я получил опыт, который поможет мне в дальнейшем.
Вот ссылка на страницу расширения в chrome store