Я, как и любой другой выпускник, переживаю по поводу экзаменов. От баллов, полученных на ЕГЭ зависит слишком многое, поэтому сейчас трудно думать о чем то другом. Чтобы не обновлять сайт check.ege.edu.ru каждые две минуты, я решил написать расширение, которое будет делать это за меня, а заодно присылать уведомления, в случае, если какой-то из экзаменов проверили.
Задача не очень сложная, но есть один неприятный момент. Сайт, на котором публикуются результаты, требует, чтобы информация о участнике, при каждом закрытии браузера, заполнялась заново. Это очень не удобно, поэтому пришлось немного по-импровизировать. Было замечено, что вся необходимая информация хранится в файлах cookie, поэтому можно просто сохранять и обновлять их когда потребуется, без необходимости вводить данные заново. Таким образом, логика работы расширения такова:
Расширения для браузера пишутся на js, оформляются с помощью html и css. В целом, разработка расширения мало чем отличается от создания сайта. Обычно любое расширение имеет следующий «скелет»:
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
Код, находящийся в этом файле будет запущен сразу после открытия браузера. Именно здесь будет находится основная логика нашего расширения
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 окна, которое открывается при нажатии на иконку расширения. В нашем случае, в этом окне будет отображаться небольшая таблица с результатами ЕГЭ.
<!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, который будет исполняться при каждом нажатии на иконку расширения. Вот его содержимое:
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
Комментарии (17)
Koneru
09.06.2019 10:48А почему вы используете Alarm, а не стандартный setInterval?
Taraflex
09.06.2019 11:25setInterval не сработает для фоновых страниц, которые браузеру позволительно выключать («persistent»: false — рекомендуемое состояние для фоновых страниц)
developer.chrome.com/extensions/background_migration
michael_kotor
09.06.2019 16:07Там же капчу просит ввести. Как вы это обходите?
algotrader2013
09.06.2019 16:08Походу через куки
Было замечено, что вся необходимая информация хранится в файлах cookie, поэтому можно просто сохранять и обновлять их когда потребуется, без необходимости вводить данные заново.
AstorS1
09.06.2019 22:14Я папа одиннадцатиклассницы, и более 12 суток нет результата даже первого экзамена. Завтра последний, волнуемся…
OBIEESupport
09.06.2019 23:13Интересно, уважаемый автор, зачем автоматизировать что-то, что человеку понадобится максимум 9 раз в жизни? Считаем — 4 экзамена в 9 классе, сочинение-допуск + 4 экзамена в 11 классе. И еще, заставка — 97 баллов по физике. У нас на 100 человек физику сдают трое, и как бы ее необходимость сильно преувеличена — в школьном учебнике даже электросхемы в картинках нарисованы.
lxsmkv
10.06.2019 05:37Что я хотел узнать из статьи? Как писать расширение для хрома на простом примере.
Что я узнал из статьи? Кусок программной реализации конкретной задачи.
Где исходники хотя бы?TimsTims
10.06.2019 08:29То что вы хотели узнать и то, о чем написал автор может не совпадать, и не всегда должно. Конкретно автор ничем вам не обязан, и он не упоминал здесь, что будет на пальцах рассказывать как писать расширение под хром. Слава богу, таких статей целая куча.
kolu4iy
Вы молодец. Но на будущее имейте ввиду: подобное расширение — лёгкий способ уложить целевой сайт, потому в реальной жизни так делать не надо. Просто представьте: миллион пользователей раз в минуту стучится на сайт.
kireevmp
Знаете, и без расширения, мне кажется, на сайт каждую минуту стучится не только миллион, а вообще все школьники, написавшие ЕГЭ.
Chaos_Theory
Вы правы. Каждый июнь он испытывает пиковые нагрузки и работает с перебоями, а в остальное время почти никому не нужен.
kolu4iy
Да, но школьник перестанет стучаться, как только увидит результат, и пойдет отмечать факт, а расширение — продолжит. Кто про него вспомнит?