Различия
Здесь показаны различия между двумя версиями данной страницы.
Предыдущая версия справа и слева Предыдущая версия Следующая версия | Предыдущая версия | ||
wiki:скрипт_для_проверки_баланса_в_peoplenet [2011/10/02 12:26] [Как работает этот код] Привел в вид, похожий на посланную статью |
— (текущий) | ||
---|---|---|---|
Строка 1: | Строка 1: | ||
- | ====== Скрипт для проверки баланса в PeopleNet ====== | ||
- | {{ :wiki:peoplenet.png|PeopleNet}} В данной статье рассматривается процесс создания скрипта для проверки баланса украинского мобильного оператора PeopleNet, который обычно используется для мобильного доступа к 3G интернету. Целью статьи является популяризация написания скриптов для облегчения ежедневных задач. | ||
- | |||
- | ---- | ||
- | |||
- | Всё началось с вопроса моего друга. «//Нельзя ли что-нибудь сделать с теперешним подсчетом трафика в PeopleNet? Ведь что-то же считает!//» Я сразу же стал теоретизировать, что таки да, можно… И через пару ночей я засел за работу и родился скрипт, которым я хочу поделиться с вами. | ||
- | |||
- | Нужно ввести читателя в курс дел. | ||
- | |||
- | В популярном пакете «777» от PeopleNet предоставляется ежедневно трафик размером 232 МБ (как бы 7 ГБ в месяц и как бы за 77 грн). Узнать остаток доступного трафика на текущие сутки можно, отправив с 3G модема SMS на служебный номер и прочитав ответ (при помощи «фирменной» программы для Windows. Отправлять SMS в Linux, с 3G модемов как-то еще не очень получается. | ||
- | |||
- | Кроме того, существует страничка биллинга, называемая //Системой самообслуживания клиентов//. Раньше я уже писал скрипт для подобных целей. Но раньше было проще. Можно было получить информацию о потраченном трафике за каждую сессию за каждый день в течение последнего месяца. Теперь же на странице красовалось одно число — количество потраченных МБ с начала месяца. С тех пор сёрфинг в сети велся практически вслепую… | ||
- | |||
- | Я почти полностью переписал скрипт, избавился от множества промежуточных шагов, временных переменных и файлов, и это пошло скрипту только на пользу. Его основу составляет одна «волшебная» строчка кода, которая получает со страницы самообслуживания число потраченных с начала месяца мегабайт: | ||
- | |||
- | <code bash>curl -s -d "X_Username=380921234567&X_Password=11223344" --url "http://my.people.net.ua/TSU/WWW/ACCOUNT_INFO/?sid=bills&rp="$(expr \( $(date +%y) - 2 \) \* 12 + $(date +%m)) | grep -A 3 EVDO | tail -n 1 | grep -o '[0-9]*'</code> | ||
- | |||
- | То же самое с разбивкой на строки: | ||
- | |||
- | <code bash>curl -s -d "X_Username=380921234567&X_Password=11223344" \ | ||
- | --url "http://my.people.net.ua/TSU/WWW/ACCOUNT_INFO/?sid=bills&rp="$(expr \( $(date +%y) - 2 \) \* 12 + $(date +%m)) | \ | ||
- | grep -A 3 EVDO | tail -n 1 | grep -o '[0-9]*'</code> | ||
- | |||
- | Здесь используется **curl** — удобная программа, которую можно в шутку назвать «веб-браузер для робота». Ее можно вызывать из своих скриптов для отсылки запросов, форм, получения и отправки страниц и файлов. Для того, чтобы получить информацию по своему номеру, вы должны изменить **380921234567** на свой номер, а **11223344** — на свой пароль для входа на страницу самообслуживания. В процессе работы будет загружена страничка размером 11,5 кБ и из нее будет выделено единственное число, которое вы и получите «на выходе». О том, что делать дальше с этим числом, мы поговорим немного позже. | ||
- | |||
- | ===== Как работает этот код ===== | ||
- | |||
- | Обо всех опциях команды curl вы сможете узнать, если выполните в терминале команду | ||
- | |||
- | <code bash>curl --help</code> | ||
- | |||
- | Такой подход к получению справки типичен для большинства команд в Linux. | ||
- | |||
- | Здесь мы используем такие ключи: | ||
- | * **-s** — «молчаливый» режим. Curl не будет печатать в терминале не нужную нам информацию о размере и скорости закачки указанной страницы; | ||
- | * **-d** и следующая строка в кавычках — данные, отсылаемые на сервер по методу POST; | ||
- | * **--url** и длинная строка, заканчивающаяся перед вертикальной чертой — адрес страницы, которую нужно получить. Сам ключ «--url» можно было бы и не писать, оставив только строку. Вертикальная черта передает страничку, загруженную командой curl, дальше, следующей команде, по конвейеру. | ||
- | |||
- | Откуда взялись параметры для ключей **-d** и **--url**? | ||
- | |||
- | Проследим работу системы самообслуживания. Зайдем при помощи обычного браузера на страницу [[http://my.people.net.ua/]]. Нас просят ввести номер телефона и пароль, затем нажать кнопку подтверждения. Далее нужно перейти по ссылке «//Ежемесячный счет//». На следующей странице выбрать нужный месяц из выпадающего списка (текущий месяц находится вверху и поэтому выбирать ничего не нужно) и нажать кнопку подтверждения. На следующей странице нужно пробежаться глазами по таблице и найти в строчке «//Передача даних EVDO//» нужное нам число. Теперь научим робота делать то же самое. | ||
- | |||
- | Для исследования страниц нам пригодится ключ **-o** команды curl. После этого ключа указываем название файла и страничка, указанная в ключе **--url** будет загружена в этот файл. | ||
- | |||
- | Итак, первый шаг: | ||
- | |||
- | <code bash>curl --url "http://my.people.net.ua/" -o "take1.html"</code> | ||
- | |||
- | Открываем полученный файл **take1.html** в текстовом редакторе (нужно хотя бы немного разбираться в html-разметке). Мы видим html-форму: | ||
- | |||
- | <file html> | ||
- | <form target="_top" action="/TSU/WWW/ACCOUNT_INFO/" method="post" name="LoginForm"> | ||
- | ... | ||
- | <input value="" name="X_Username" size="9" title="Введіть номер Вашого телефону" type="text"> | ||
- | ... | ||
- | <input name="X_Password" size="9" title="Введіть Ваш пароль" type="password"> | ||
- | ... | ||
- | <input value="Вхід" type="submit"> | ||
- | ... | ||
- | </form> | ||
- | </file> | ||
- | |||
- | Я удалил всё, не относящееся к делу, чтобы можно было сосредоточиться на нашем задании. Итак, данные формы отправляются методом **POST**, значит, воспользуемся ключом **-d** команды curl. Вот, если бы метод был **GET**, то можно было бы не городить огород, а дописать передаваемые данные прямо в строку адреса (примерно так: [[http://наш.длинный/адрес?параметр1=значение1&параметр2=значение2]]). | ||
- | |||
- | Итак, из анализа формы становится понятно, что при нажатии кнопки подтверждения данные формы отсылаются по адресу http://my.people.net.ua/TSU/WWW/ACCOUNT_INFO/ и эти данные — **X_Username=номер телефона** и **X_Password=пароль**. | ||
- | |||
- | Второй шаг наших раскопок: | ||
- | |||
- | <code bash>curl -d "X_Username=380921234567&X_Password=11223344" \ | ||
- | --url "http://my.people.net.ua/TSU/WWW/ACCOUNT_INFO/" \ | ||
- | -o "take2.html"</code> | ||
- | |||
- | Просмотрев загруженную страничку, мы видим, что //да//, нас успешно пустили в систему самообслуживания. Теперь нас интересует ссылка: | ||
- | |||
- | <file html><a href="http://my.people.net.ua/TSU/WWW/ACCOUNT_INFO?sid=bills">Ежемесячный счет</a></file> | ||
- | |||
- | Я снова убрал всё лишнее. Попробуем: | ||
- | |||
- | <code bash>curl --url "http://my.people.net.ua/TSU/WWW/ACCOUNT_INFO?sid=bills" -o "take3.html"</code> | ||
- | |||
- | Получаем страничку с ошибкой. Хм, попробуем так: | ||
- | |||
- | <code bash>curl --url "http://my.people.net.ua/TSU/WWW/ACCOUNT_INFO/?sid=bills" -o "take3.html"</code> | ||
- | |||
- | Теперь получаем первоначальную страничку для входа в систему самообслуживания. Нас //забыли// и снова предлагают ввести номер и пароль! Попробуем не городить огород, а просто объединим две команды, два адреса в один: | ||
- | |||
- | <code bash>curl -d "X_Username=380921234567&X_Password=11223344" \ | ||
- | --url "http://my.people.net.ua/TSU/WWW/ACCOUNT_INFO/?sid=bills" \ | ||
- | -o "take3a.html"</code> | ||
- | |||
- | Так! Мы продвинулись дальше! Просматривая страницу, находим в ней форму для выбора месяца: | ||
- | |||
- | <file html><form action="http://my.people.net.ua/TSU/WWW/ACCOUNT_INFO" method="GET"> | ||
- | <input type="hidden" name="sid" value="bills"> | ||
- | <select name="rp"> | ||
- | <option value="117" selected>вересень 2011 року</option> | ||
- | <option value="116">серпень 2011 року</option> | ||
- | <option value="115">липень 2011 року</option> | ||
- | <option value="114">червень 2011 року</option> | ||
- | <option value="113">травень 2011 року</option> | ||
- | <option value="112">квітень 2011 року</option> | ||
- | <option value="111">березень 2011 року</option> | ||
- | <option value="110">лютий 2011 року</option> | ||
- | <option value="109">січень 2011 року</option> | ||
- | <option value="108">грудень 2010 року</option> | ||
- | <option value="107">листопад 2010 року</option> | ||
- | </select> | ||
- | <input type="submit" value="Показати"> | ||
- | </form> | ||
- | </file> | ||
- | |||
- | Я снова убрал всё лишнее из html-разметки. В зависимости от вашего «стажа» в PeopleNet длина списка у вас будет другая. Итак, адрес для отсылки формы ясен; метод, кстати — GET, значит, пишем параметры прямо в строку адреса. Имеется скрытая (hidden) переменная с именем **sid** и значением //bills//. Вторая переменная с именем **rp** и нужным нам значением //117//. Формируем адрес: | ||
- | |||
- | <code>http://my.people.net.ua/TSU/WWW/ACCOUNT_INFO/?sid=bills&rp=117</code> | ||
- | |||
- | Пробуем снова совместить команды: | ||
- | |||
- | <code bash>curl -d "X_Username=380921234567&X_Password=11223344" \ | ||
- | --url "http://my.people.net.ua/TSU/WWW/ACCOUNT_INFO/?sid=bills&rp=117" \ | ||
- | -o "take4.html"</code> | ||
- | |||
- | Да, мы продвинулись еще дальше. Правда, такого же восторга уже нет. Остается работа. И она заключается в следующем. | ||
- | |||
- | Во-первых, каждый месяц число в параметре **rp** будет меняться. Во-вторых, нам нужно проанализировать код страницы. Подберем формулу для расчета числа: | ||
- | |||
- | <code bash>rp = ( год - 2 ) * 12 + месяц</code> | ||
- | |||
- | Номер года (две последние цифры) и номер месяца (две цифры) мы можем получить соответствующими командами: | ||
- | |||
- | <code bash> | ||
- | date +%y | ||
- | date +%m | ||
- | </code> | ||
- | |||
- | Если окружить команду такой оберткой — **$(команда)**, то тогда результат работы этой команды будет представлен в виде строки и его можно будет использовать для дальнейших вычислений в более сложных командах. Для математических расчетов используем команду **expr**. | ||
- | |||
- | <code bash>expr ( $(date +%y) - 2 ) * 12 + $(date +%m)</code> | ||
- | |||
- | Получаем ошибку, говорящую о некорректном синтаксисе, курим маны и «экранируем» скобки, входящие в нашу формулу, а также звездочку (знак умножения), поставив перед ними бэкслэш (**\**): | ||
- | |||
- | <code bash>expr \( $(date +%y) - 2 \) \* 12 + $(date +%m)</code> | ||
- | |||
- | Получаем 117. Что нам и требовалось! | ||
- | |||
- | Теперь окружаем эту команду при помощи **$(...)** и подставляем ее вместо числа 117 в нашу супер-команду curl: | ||
- | |||
- | <code bash>curl -s -d "X_Username=380921234567&X_Password=11223344" \ | ||
- | --url "http://my.people.net.ua/TSU/WWW/ACCOUNT_INFO/?sid=bills&rp="$(expr \( $(date +%y) - 2 \) \* 12 + $(date +%m))</code> | ||
- | |||
- | Заметьте, что кавычки закрываются после «rp=» и сразу же мы пишем обернутую команду, таким образом, результат команды (число 117) дописывается к строке. | ||
- | |||
- | Теперь пришло время «во-вторых» — анализ кода страницы. Вы помните, как выглядит табличка, когда вы заходили через браузер? Ищем строчку с аббревиатурой //EVDO// и находим такой участок html-разметки: | ||
- | |||
- | <file html> | ||
- | <tr> | ||
- | <td> | ||
- | <i> Передача даних EVDO</i> | ||
- | </td> | ||
- | <td class="ar4"> | ||
- | <i> 224</i> | ||
- | </td> | ||
- | <td class="ar4"> | ||
- | <i>0.00</i> | ||
- | </td> | ||
- | </tr> | ||
- | </file> | ||
- | |||
- | Здесь я не стал убирать ничего. Нам нужно «научить робота» выделять вот это число — **224**. | ||
- | |||
- | Давайте поищем на странице слово «EVDO» (в текстовом редакторе, в котором вы просматриваете эту страничку). Нашли только один раз, хорошо. Курим маны. Пользуемся командой **grep**. Команда **grep EVDO** выдает нам только строчку, в которой найдено слово EVDO, а команда **grep -A 3 EVDO** выдает нам эту строчку и еще три следующих за ней строки. Как раз в третьей строке находится наше число! Итак, код: | ||
- | |||
- | <file html>cat "take4.html" | grep -A 3 EVDO</file> | ||
- | |||
- | Здесь мы при помощи команды **cat** выводим содержимое файла take4.html и при помощи вертикальной черты передаем его дальше по конвейеру команде **grep**. Получаем: | ||
- | |||
- | <file html> | ||
- | <i> Передача даних EVDO</i> | ||
- | </td> | ||
- | <td class="ar4"> | ||
- | <i> 224</i> | ||
- | </file> | ||
- | |||
- | Теперь «откусим» только последнюю строку при помощи команды **tail**: | ||
- | |||
- | <code bash>cat "take4.html" | grep -A 3 EVDO | tail -n 1</code> | ||
- | |||
- | Получаем: | ||
- | |||
- | <file html> <i>�224</i></file> | ||
- | |||
- | Вы заметили некий гаденький символ перед цифрами? Так в консоль выводится символ неразрывного пробела, который непонятно зачем всунули разработчики этой странички. В старой версии скрипта я бы написал несколько команд, которые последовательно по конвейеру, удаляли бы из строки ненужные нам символы. Сначала бы заменили пробел(ы) на ничто (т. е. удалили их), затем «<i>», после «</i>», и, наконец, этот гаденький символ. | ||
- | |||
- | Синтаксис команды **sed** (для замены строк) прост: | ||
- | |||
- | <code bash>sed -e 's/что-менять/на-что-менять/g'</code> | ||
- | |||
- | Ключ **g** говорит, что менять нужно глобально, а не только первый попавшийся случай. Так, команда: | ||
- | |||
- | <code bash>sed -e 's/ //g; s/<i>//g; s/<\/i>//g'</code> | ||
- | |||
- | последовательно заменит все пробелы на «ничто», затем «<i>» и «</i>». А, вот, с //этим символом// не всё так просто. Кодировка скрипта, конечно же, UTF-8, а кодировка странички — windows-1251. Поэтому, команда **sed** ничего не найдет. А, если же сохранить скрипт в кодировке 1251, то мы не сможем выводить этим скриптом русские буквы. А, если, сохранить в 1251, вставить символ в скрипт, а затем открыть как UTF-8, то текстовый редактор откажется работать с этим скриптом. Да-а… | ||
- | |||
- | Отмечу, что ту же задачу можно было бы решить по-другому: | ||
- | |||
- | <code bash>cut -d ">" -f 2 | cut -d "<" -f 1</code> | ||
- | |||
- | Здесь сначала мы разбиваем нашу строку на части. Разделитель частей — символ «>», берем вторую часть. Затем полученную строку снова разбиваем на части, но уже символом «<» и берем первую часть. | ||
- | |||
- | То, что задачу можно решить как минимум двумя разными способами — тоже типично для Linux. | ||
- | |||
- | Всё хорошо, но число с этим символом в начале нельзя подставлять в математические выражения — получим ошибку! Покурив маны, я нашел простое и элегантное решение: | ||
- | |||
- | <code bash>grep -o '[0-9]*'</code> | ||
- | |||
- | В переводе на русский язык это значит: выдать из исходной строки только символы из интервала 0-9 (цифры), а звездочка обозначает, что этих цифр может быть произвольное количество. | ||
- | |||
- | Вот и всё! Получился скрипт в одну строку, который выполняет такую сложную задачу! Вот в этом и заключается сила командной строки Linux, профессионалы могут сделать в консоли всё что угодно. А новички не верят, говорят, устарело. Неправда… | ||
- | ===== Обрабатываем полученное значение ===== | ||
- | |||
- | Если ваш тарифный план не подразумевает посуточную разбивку трафика (400 МБ в месяц), то на этом всё, вы можете вывести это число на экран (об этом позже). Если же в вашем тарифе существует суточный лимит (например, 232 МБ/сут., как в тарифном плане «777»; либо 300 МБ/сут., как в другом тарифном плане, названия которого я не знаю), то пойдем дальше. | ||
- | |||
- | Идея такая. При самом первом за сутки подключении к интернету мы должны запустить наш скрипт и запомнить полученное число. При последующих подключениях за эти же сутки число будет увеличиваться, и тогда по разнице мы можем узнать, сколько мегабайт мы потратили. | ||
- | |||
- | Удобно, когда скрипт сам будет за нас записывать это число и сам будет считать остаток. Лучше всего дописать вызов этого скрипта в конец процедуры подключения к интернету; таким образом, как только вы подключитесь к интернету, так сразу, не потратив еще нисколько мегабайт, узнаете число со страницы самообслуживания. А потом, когда вы присоединяетесь к интернету в следующий раз, скрипт должен снова узнать число со страницы самообслуживания, найти разницу (потраченные МБ) и отнять от суточного лимита эту разницу. Задача ясна? Беремся? | ||
- | |||
- | Для начала, давайте, отведем отдельный файл для такой важной задачи — хранения количества потраченных мегабайт в начале суток. В нём будет храниться одно число. Пусть его формат будет таким: **MMDDxxxx** | ||
- | где: **MM** — месяц, **DD** — день, **xxxx** — мегабайты. Весьма компактно. | ||
- | |||
- | Мы можем определить текущую дату при помощи команды | ||
- | <code bash>date +%m%d</code> | ||
- | А выделить дату из файла можно такой командой (взять первые 4 символа из файла): | ||
- | <code bash>cut -c -4 файл</code> | ||
- | Параметр «-4» это сокращенная запись «с начала и до четвертого». Полностью можно было бы записать «1-4», что значит «с первого по четвертый». | ||
- | Количество мегабайт выделяется из файла командой: | ||
- | cut -c 5- файл | ||
- | Что тоже является сокращенной формой «с пятого и до конца». | ||
- | |||
- | Теперь продумаем возможные ситуации. | ||
- | * Что, если нет подключения к интернету, а мы запустили скрипт? В результате работы нашей супер-команды мы получим пустую строку. Говорим «Ошибка связи». | ||
- | * Что, если файла нету? Получаем данные со страницы самообслуживания, создаем файл и заносим в него цифры. Говорим, что на сегодня осталось максимально возможное количество МБ. | ||
- | * Что, если дата в файле является устаревшей (вчера, позавчера…)? Значит, сегодня мы еще не пользовались интернетом. Получаем данные и заносим в файл. Говорим, что на сегодня осталось максимально возможное количество МБ. | ||
- | * Что, если дата сегодняшняя? Файл не меняем. Находим количество потраченных МБ. От суточного лимита отнимаем потраченные. Выдаём число. | ||
- | |||
- | Теперь схематично опишем алгоритм. | ||
- | <file> | ||
- | ПОЛУЧИТЬ «КОЛИЧЕСТВО_МБ» | ||
- | ЕСЛИ [ «КОЛИЧЕСТВО_МБ» пустое ] | ||
- | |ТОГДА | ||
- | | СООБЩЕНИЕ = «Ошибка связи» | ||
- | |ИНАЧЕ | ||
- | | УЗНАТЬ «текущую дату» (ММДД) | ||
- | | ЕСЛИ [ файл есть ] И [ дата в файле (ММДД) совпадает с текущей (ММДД) ] | ||
- | | |ТОГДА | ||
- | | | «ОСТАЛОСЬ» = («xxxx из файла» + «суточный лимит» - «КОЛИЧЕСТВО_МБ») | ||
- | | |ИНАЧЕ | ||
- | | | записать «текущую дату (ММДД)» и «КОЛИЧЕСТВО_МБ» в файл; | ||
- | | | «ОСТАЛОСЬ» = «СУТОЧНЫЙ ЛИМИТ» | ||
- | | КОНЕЦ_ЕСЛИ | ||
- | | СООБЩЕНИЕ = «На сегодня осталось: «ОСТАЛОСЬ» МБ» | ||
- | КОНЕЦ_ЕСЛИ | ||
- | |||
- | ВЫДАТЬ «СООБЩЕНИЕ» | ||
- | </file> | ||
- | Алгоритм понятен? Замечательно, если да! Теперь запишем его при помощи консольных команд на языке BASH. | ||
- | Указываем, что наш СУТОЧНЫЙ ЛИМИТ равен 232 МБ: | ||
- | <file>LIM=232</file> | ||
- | В переменной **PN** сохраняем папку, в которую мы положили всё нужное для работы нашего скрипта — сам скрипт, файл для хранения DDMMxxxx и даже логотип **PeopleNet**. Папка эта называется peoplenet и лежит она в нашей домашней папке (на что указывает системная переменная **$HOME**), которая, конечно же разная для разных пользователей. Но, благодаря такому подходу, ничего в скрипте менять не нужно. Переменную **PN** мы ввели для краткости. Назовем файл для хранения DDMMxxxx просто «**pn**», тогда путь к нему мы можем записать так: "**$PN/pn**"; картинка же называется pn.png и путь к ней будет "**$PN/pn.png**". | ||
- | <code bash> | ||
- | PN=$HOME/peoplenet | ||
- | |||
- | MB=$(curl -s -d "X_Username=380922530191&X_Password=64506822" --url "http://my.people.net.ua/TSU/WWW/ACCOUNT_INFO/?sid=bills&rp="$(expr \( $(date +%y) - 2 \) \* 12 + $(date +%m)) | grep -A 3 EVDO | tail -n 1 | grep -o '[0-9]*') | ||
- | |||
- | if [ -z $MB ] | ||
- | then | ||
- | MESS="Ошибка связи" | ||
- | else | ||
- | DT=$(date +%m%d) | ||
- | if [ -e $PN/pn ] && [ $(cut -c -4 $PN/pn) -eq $DT ] | ||
- | then | ||
- | OM=$(expr $(cut -c 5- $PN/pn) + $LIM - $MB) | ||
- | else | ||
- | echo $DT$MB > $PN/pn; OM=$LIM | ||
- | fi | ||
- | MESS="На сегодня осталось: $OM МБ" | ||
- | fi | ||
- | |||
- | notify-send "PeopleNet" "$MESS" -i $PN/pn.png | ||
- | </code> | ||
- | |||
- | Немного нужно рассказать о последней команде, так? Эта команда должна выполняться на любом дистрибутиве, поддерживающем стандарты. Она выдает примерно такое вот сообщение: | ||
- | |||
- | {{:wiki:peoplenet_script_example_1.png}} | ||
- | |||
- | При наведении на него мышки, оно тускнеет и пропадает, не мешая работать с другими окнами, а через несколько секунд (в зависимости от количества текста в сообщении) пропадает. | ||
- | |||
- | {{:wiki:peoplenet_script_example_2.png}} | ||
- | |||
- | Хотите поместить на рабочий стол значок для запуска нашего скрипта? Нажмите на рабочем столе правой кнопкой — Создать кнопку запуска… и заполните поля. Следующий рисунок показывает, как это сделал я. | ||
- | |||
- | ===== Всё? Нет! Продолжение ===== | ||
- | |||
- | В процессе написания статьи мне захотелось получить еще больше функционала от моего скрипта. На счету у меня сегодня «минус», но скрипт по прежнему щедро выдает мне мегабайты. Такую ситуацию надо отслеживать. Заодно можно узнать, на сколько дней хватит денег и выдать дату, когда нужно пополнить счет. | ||
- | |||
- | Так как страницу, загруженную из системы самообслуживания, теперь нужно будет дважды проанализировать, разобьем нашу супер-команду на две части. Запомним страницу в переменную **PAGE**, а затем найдем в ней всё, что нам нужно: | ||
- | <code bash> | ||
- | PAGE=$(curl -s -d "X_Username=380921234567&X_Password=11223344" --url "http://my.people.net.ua/TSU/WWW/ACCOUNT_INFO/?sid=bills&rp="$(expr \( $(date +%y) - 2 \) \* 12 + $(date +%m))) | ||
- | |||
- | MB=$(echo "$PAGE" | grep -A 3 EVDO | tail -n 1 | grep -o '[0-9]*') | ||
- | </code> | ||
- | Теперь посмотрим, как из текста страницы можно выделить остаток на счету. Просмотрим файл **take4.html**, который мы загрузили в процессе экспериментов (эта же страница будет загружена в переменную **PAGE**). Мы видим строки | ||
- | |||
- | <file> | ||
- | <tr> | ||
- | <td colspan="2"> | ||
- | <b> | ||
- | <font>Поточний баланс на 14.09.2011</font> | ||
- | </b> | ||
- | </td> | ||
- | <td class="ar"> | ||
- | <b> | ||
- | <font color="#a00000">-1.09</font> | ||
- | </b> | ||
- | </td> | ||
- | </tr> | ||
- | </file> | ||
- | Чтобы не связываться с русскими буквами в другой кодировке (хотя, при необходимости, страницу можно конвертировать), будем искать текст «14.09.2011» — это текущая дата на момент написания статьи. Дату в таком формате мы можем получить при помощи команды: | ||
- | <code bash>date +%d.%m.%Y</code> | ||
- | Дальше — технология отработана. Выделяем пятую строчку после найденной, а затем выделяем содержимое между символами «>» и «<». В завершение, удалим точку, чтобы перевести сумму в копейки, так как консольная команда expr работает только с целыми числами: | ||
- | <code bash>MONEY=$(echo "$PAGE" | grep -A 5 $(date +%d.%m.%Y) | tail -n 1 | cut -d ">" -f 2 | cut -d "<" -f 1 | sed -e 's/\.//')</code> | ||
- | Если число меньше нуля, выведем сообщение //«Услуга недоступна. Пополните счет!»// | ||
- | |||
- | Согласно справочнику тарифов PeopleNet, каждый день со счёта снимается сумма **2,64 грн**. Давайте разделим полученный баланс на тариф и узнаем, на сколько дней нам хватит денег: | ||
- | <code bash>TARIFF=264 | ||
- | DAYS=$(expr $MONEY / $TARIFF)</code> | ||
- | Если денег меньше, чем 264, то мы получим 0. Это значит, что ночью будет снята сумма тарифа и на счету будет меньше нуля. Интернет завтра будет недоступен. Выведем сообщение //«Пополните счет сегодня»//. Если получим 1, то выведем //«Пополните счет завтра»//. Для других чисел выведем что-то вроде //«Осталось 3 дня. Пополните 31.09.2011 г.»// | ||
- | |||
- | Здесь есть две «проблемы». Во-первых, корректная выдача слов //«день»//, //«дня»//, //«дней»//. Во-вторых, расчет даты в будущем, на расстоянии несколько дней от сегодняшней даты. На самом деле это — не проблемы. Поверьте — всё решаемо! | ||
- | |||
- | Во-первых, я вспомнил время, когда занимался локализацией строк в программах при помощи Gettext. Там была интересная строчка кода, которая определяет форму слова. Чтобы не рыться в старых файлах, достаточно почитать [[http://ru.wikipedia.org/wiki/Gettext|страничку Gettext в Википедии]]. Вот эта строка: | ||
- | <code bash>plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)</code> | ||
- | Как ее приспособить для нашего скрипта? Оказывается, достаточно окружить ее двойными скобками и пробелами. Теперь, если plural=**0**, то пишем «день», если **1** — то «дня», если **2** — то «дней». Создадим массив со словами: | ||
- | <code bash>day=( день дня дней )</code> | ||
- | И будем выдавать нужное слово (по номеру элемента массива) командой | ||
- | <code bash>${day[$plural]}</code> | ||
- | Теперь займемся расчетом дат. Google, как обычно, помогает. На этот раз мне понравилась [[http://www.unix.com/tips-tutorials/31944-simple-date-time-calulation-bash.html|вот эта ссылка]]. | ||
- | Так много функционала мне не надо, поэтому я максимально сокращаю скрипт под свою задачу. | ||
- | # количество секунд, прошедших с 01.01.1970 до настоящего момента | ||
- | TODAY=$(date --utc +%s) | ||
- | # прибавляем нужное количество секунд (в сутках их 86400) | ||
- | DATESEC=$(expr $TODAY + \( $DAYS + 1 \) \* 86400) | ||
- | # рассчитываем дату в будущем и выводим ее в формате ДД.ММ.ГГГГ | ||
- | DATE2=$(date --utc --date "1970-01-01 $DATESEC sec" "+%d.%m.%Y") | ||
- | </code> | ||
- | Можно всё это собрать в одну строку: | ||
- | <code bash>DATE2=$(date --utc --date "1970-01-01 $(expr $(date --utc +%s) + \( $DAYS + 1 \) \* 86400) sec" "+%d.%m.%Y")</code> | ||
- | Теперь — весь скрипт целиком. Он исправно выполняет поставленные задачи. | ||
- | <code bash> | ||
- | #!/bin/bash | ||
- | |||
- | LIM=232 | ||
- | TARIFF=264 | ||
- | PN=$HOME/peoplenet | ||
- | |||
- | PAGE=$(curl -s -d "X_Username=380921234567&X_Password=11223344" --url "http://my.people.net.ua/TSU/WWW/ACCOUNT_INFO/?sid=bills&rp="$(expr \( $(date +%y) - 2 \) \* 12 + $(date +%m))) | ||
- | |||
- | MB=$(echo "$PAGE" | grep -A 3 EVDO | tail -n 1 | grep -o '[0-9]*') | ||
- | |||
- | MONEY=$(echo "$PAGE" | grep -A 5 $(date +%d.%m.%Y) | tail -n 1 | cut -d ">" -f 2 | cut -d "<" -f 1 | sed -e 's/\.//') | ||
- | |||
- | if [ -z $MB ] | ||
- | then | ||
- | MESS="Ошибка связи" | ||
- | else | ||
- | if [ $MONEY -lt 0 ] | ||
- | then | ||
- | MESS="Услуга недоступна. Пополните счет!" | ||
- | else | ||
- | DAYS=$(expr $MONEY / $TARIFF); n=$DAYS | ||
- | day=( день дня дней ) | ||
- | (( plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2) )) | ||
- | case "$DAYS" in | ||
- | 0) MESS2="Пополните счет сегодня";; | ||
- | 1) MESS2="Пополните счет завтра";; | ||
- | *) MESS2="Осталось $DAYS ${day[$plural]}. Пополните $(date --utc --date "1970-01-01 $(expr $(date --utc +%s) + \( $DAYS + 1 \) \* 86400) sec" "+%d.%m.%Y") г.";; | ||
- | esac | ||
- | |||
- | DT=$(date +%m%d) | ||
- | if [ -e $PN/pn ] && [ $(cut -c -4 $PN/pn) -eq $DT ] | ||
- | then | ||
- | OM=$(expr $(cut -c 5- $PN/pn) + $LIM - $MB) | ||
- | else | ||
- | echo $DT$MB > $PN/pn; OM=$LIM | ||
- | fi | ||
- | MESS="На сегодня осталось: $OM МБ\n""$MESS2" | ||
- | fi | ||
- | fi | ||
- | |||
- | notify-send "PeopleNet" "$MESS" -i $PN/pn.png | ||
- | </code> | ||
- | По-моему, получилось неплохо. | ||
- | |||
- | А дальше всё зависит от ваших потребностей и фантазии. Можно, например, вести ежедневную статистику (не)потраченного трафика. Можно параллельно вести подсчет трафика и сравнивать с тем, что выдается на странице. Можно проверить, действительно ли снимают по 2,64 каждый день? И т. п. А на входе были всего два числа… | ||
- | |||
- | ===== Используемая литература ===== | ||
- | Пишу я редко, как скрипты, так и статьи. Поэтому, конечно же, через время забываю разные мелочи. Лучший помощник по программированию на BASH — книга «Advanced Bash-Scripting Guide» автора Mendel Cooper. Русский перевод этой книги («Искусство программирования на языке сценариев командной оболочки», перевел Андрей Киселев) можно легко найти в интернете, например, | ||
- | * [[http://www.opennet.ru/docs/RUS/bash_scripting_guide/|Версия 1.8]] на OpenNet.ru | ||
- | * [[http://gordin.us/sergo/abs-guide/index.html|Версия 2.5]] на gordin.us | ||
- | |||
- | В работе конкретно над этой задачей также помогли следующие материалы: | ||
- | * [[http://people.net.ua/ru/tariffs/prepaid/anonymouse/|Анонимные тарифные планы PeopleNet]] | ||
- | * [[wpru>Gettext]] — Википедия | ||
- | * [[http://www.unix.com/tips-tutorials/31944-simple-date-time-calulation-bash.html|Simple date and time calulation in BASH - The UNIX and Linux Forums]] | ||
- | |||
- | \\ \\ | ||
- | |||
- | ^Автор^Раздел^ | ||
- | |Бобылёв Алексей (Lexeii)|как сделать ...| | ||
- | |||
- | {{tag>Конкурс}} |