Для чего это нужно?
Стоит рассмотреть два уровня использования подобной возможности:
- Обычная, бытовая потребность отправки относительно длинного сообщения (если вы конечно не обладаете такой же скоростью печати на телефоне, как и на компьютере)
- Необычная, гиковская потребность получать рассылочную информацию там, где нет компьютера, смешанная с нежеланием платить за доставку этой информации лишние деньги
Обычное применение
Итак, наверняка многие сталкивались с ситуацией, когда необходимо написать относительно длинное смс-сообщение:
- скопипастить кому-нибудь нужную информацию
- подробно описать какие-нибудь детали встречи, когда у вашего собеседника поговорить нет возможности
- ну или банально написать что-то в духе тех самых проиндесированных смс-ок :3
Необычное применение
Здесь варианты использования ограничены только вашей фантазией и умениями парсить нужные информационные потоки, например:
- прогноз погоды
- заголовки rss-ленты
- твиттер-лента
- данные по нагрузке вашего сервера
- ?????
- PROFIT!
Выбор сервиса для отправки
Сразу спешу предупредить, что изначально всё делалось для себя, поэтому решение привязано к московскому мегафону, но для других регионов у мегафона тоже есть подобные сервисы, надеюсь и для других операторов.
Очевидно, что для бытового использования крайне необходимо отправлять сообщения со своего же номера и без рекламы, поэтому сервис sendsms.megafon.ru не подходит, тем более надо вводить капчу, да и как показывать её в консоли? А если вы так же любите фреймбуфер, как люблю его я? А если учесть недавний инцидент с проиндесированными смс-ками?
К счастью, у мегафона есть система самообслуживания абонентов «Сервис-Гид», которой я довольно давно пользовался именно для этих целей, да и другие полезные функции там есть, а защищённость https внушает некоторое доверие.
Относительно недавно при входе в сервис-гид перестали предлагать ввести капчу, что заставило меня задуматься о использовании этого сайта в своих «грязных» целях.
На всякий случай отвечу тем, кто недоумевает, зачем писать консольный скрипт вместо того, чтобы зайти на сайт и нажать три кнопки: «войти» → «меню: отправка смс» → «пункт: отправка смс»:
- хотелось бы иметь прямую ссылку на форму отправки
- в текстовых браузерах по умолчанию не включена поддержка javascript
- скрипт можно использовать не только для обычного применения, но и автоматизировать рассылку.
Анализ сайта Сервис-Гида
Заходим на страницу сервис-гида и видим следующее:
- как получить, изменить, восстановить пароль
- специальные замечания для пользователей тарифа мегафон-интернет
- как получить ссылку на Java-приложение Сервис-Гид для телефона
Последний пункт мне показался очень привлекательным, тем более, что трафик обещают не тарифицировать, но, к сожалению, на моём относительно древнем телефоне Samsung SGH-E200 установить не получилось из-за большого объёма приложения (лишние файлы тоже выкинуть не вышло).
Переходим к анализу формы входа на сайт. Я пользуюсь Mozilla Firefox и Firebug, в Google Chrome есть свой инструментарий для этих целей.
Открываем вкладку «Консоль», включаем отображение AJAX-запросов, нажимаем кнопку «Не очищать» (чтобы при перенаправлении страницы не затёрлись эти самые запросы) и пытаемся зайти на сайт.
POST-запрос:
www.serviceguide.megafonmoscow.ru/ps/scc/php/check.php?CHANNEL=WWW&LOGIN=ваш_логин&PASSWORD=ваш_пароль
Ответ:
<SESSION_ID>AAAAkljkLFJ9JKJk3fowmcoOW3fds</SESSION_ID>
<LANG_ID>1</LANG_ID>
<AUTH_MODE>U</AUTH_MODE>
Вроде всё понятно, легко получаем SESSION_ID.
Написание скрипта
Внимательный читатель заметит, что при перенаправлении должен выполниться ещё один POST-запрос:
www.serviceguide.megafonmoscow.ru/SCWWW/ACCOUNT_INFO?CHANNEL=WWW&P_USER_LANG_ID=1&SESSION_ID=AAAAkljkLFJ9JKJk3fowmcoOW3fds
Тут ответ уже намного сложнее:
…
<text-phrase xmlns:xalan=«xml.apache.org/xalan» id=«js-dict-form»></text-phrase>
…
Особого желания разбирать этот формат у меня не было, поэтому я воспользовался уже знакомыми мне xpath и python-lxml (вот неплохой пример использования).
Допустим, получим данные о балансе на счету:
Код намеренно написан без проверок на корректность выполнения, чтобы не загромождать пост кучей try-except.
#!/usr/bin/python
import urllib
from lxml import etree
from StringIO import StringIO
def get_root(url, params):
params = urllib.urlencode(params)
raw_response = urllib.urlopen(url, params).read()
parser = etree.HTMLParser()
tree = etree.parse(StringIO(raw_response), parser)
root = tree.getroot()
return root
login='ваш номер телефона'
password='ваш пароль'
login_url="https://www.serviceguide.megafonmoscow.ru/ps/scc/php/check.php?"
login_params={'CHANNEL':'WWW', 'LOGIN':login, 'PASSWORD':password}
login_root=get_root(login_url,login_params)
session_id = login_root.find(".//session_id").text
lang_id = login_root.find(".//lang_id").text
print 'session_id=',session_id
account_info_url="https://www.serviceguide.megafonmoscow.ru/SCWWW/ACCOUNT_INFO?"
account_info_params={'CHANNEL':'WWW', 'P_USER_LANG_ID':lang_id, 'SESSION_ID':session_id}
account_info_root=get_root(account_info_url,account_info_params)
balance=account_info_root.find(".//div[@class='balance_good td_def']").text
print balance
Теперь переходим непосредственно к отправке смс:
# это продолжение предыдущего куска говнокода
prefix='926'
print 'prefix=', prefix
addr=raw_input('number (7 digits: 1234567): ')
msg=raw_input('message: ')
msg=msg.decode('utf8').encode('cp1251')
sms_url="https://www.serviceguide.megafonmoscow.ru/SCWWW/SUBS_SEND_SMS_ACTION?"
sms_params={'CUR_SUBS_MSISDN': login, 'prefix': prefix, 'addr': addr, 'CHANNEL': 'WWW', 'SESSION_ID': session_id, 'SUBSCRIBER_MSISDN': login, 'MSISDN_TO': prefix+addr, 'P_USER_LANG_ID': lang_id, 'MESSAGE': msg}
sms_root=get_root(sms_url,sms_params)
divs=sms_root.findall(".//div")
for div in divs:
print div.text.strip()
Ну и было бы неплохо выполнить выход из системы:
# это ещё одно продолжение предыдущего куска кода
logout_params={'CHANNEL':'WWW', 'CUR_SUBS_MSISDN':login, 'P_USER_LANG_ID':lang_id, 'SESSION_ID':session_id, 'SUBSCRIBER_MSISDN':login}
logout_url="https://www.serviceguide.megafonmoscow.ru/SCWWW/CLOSE_SESSION?"
logout_root=get_root(logout_url,logout_params)
logout_result = etree.tostring(logout_root, pretty_print=True, method="html")
print logout_result
Несложно написать скрипты, которые будут отправлять вам (или кому-то ещё) смс с нужной вам информацией: твиттер-лента, rss, прогноз погоды и прочее. Привязать это к расписании или каким-либо событиям тоже не составит особого труда.
Подведение итогов
Безусловно, многие приёмы, использованные в фрагментах скрипта, не являются примерами хорошего кода. Возможно, стоит использовать ssl-соединение вместо простого urllib.urlopen(). Возможно, что не стоит полностью переводить страницу в объект etree, а попробовать разобраться с xmlns:xalan. Но одна из целей статьи — показать, что есть удобный способ отправлять смс, не набирая его на клавиатуре телефона, а также предоставить инструмент для автоматических смс-сообщений с рассылочной информацией.
В планах написать статью про скрипт для консольного просмотра количества билетов на поезда с сайта РЖД. В принципе, легко можно осуществить связь этих двух скриптов: присылать смс-уведомление о том, что появились нужные вам билеты.
UPD:
Спасибо за ценные комментарии, краткие итоги:
- в некоторых регионах отправка смс через сервис-гид платная, будьте внимательны
- кое-где требуется ввод капчи, возможно где-то её убрать нельзя, где-то можно юзать такие трюки:
- «Настройка сервис-гид» -> «Автоматический доступ системам» — у некоторых убирает капчу
- поменять юзер агент на айфоновский/андроидовский и зайти в сервис гид — переадресовывает на другую страницу, где нет капчи
Сравнение способов отправки:
Способ | Стоимость | Номер | Примечание |
---|---|---|---|
Сервис-Гид | Бесплатно | Свой | Не для всех регионов бесплатно, а кое-где ещё и капча осталась |
SMS+ | 2 руб/день | Свой | Не более 70 смс в день, зато там есть и другие полезные услуги |
PHP-библиотека для SOAP API Мегафона | Зависит от вашего тарифа | Свой | За библиотеку спасибо synchrone |
GSM-modem | Зависит от вашего тарифа | Свой | Для любителей Arduino ссылка от Prometheus |
Через почтовый сервер | Бесплатно | Другой | Не пользовался, информация со слов interrupt_controller |