-
Умирает ли РСС?
В последнее время в Сети то и дело пишут о том, что формат РСС умирает. Дескать, все продвинутые читают Твиттер и Гугл+, все актуальное и интересное там, а РСС для неудачников.
Поговорим об этом.
Чтобы развеять миф, озвученный в первом предложении, необходимо и достаточно ответить на два вопроса:
- Какие преимущества есть у РСС-лент?
- Что произойдет, если формат действительно умрет, и все сайты мира отключат РСС?
Преимущества
Во-первых, РСС — очень простой формат, обычная XML-ка.
Взгляните на официальный документ — структура совершенно прозрачна. Причем не обязательно соблюдать условности вроде тега
<title>
— современные приложения в состоянии разобрать даже самые невалидные ленты. Например, сайт slon.ru отдает ленту только с тегами<description>
,<link>
и<pubDate>
, что никак не мешает ее чтению.Во-вторых — открытость и минималистичность формата делает работу с ним очень удобной. Построение и парсинг XML — обычная рутинная задача веб-разработчика. Собрал XML и сохранил на диск — приложение пользователя само его заберет и распарсит. Никаких OAuth-танцев, токенов и авторизаций.
Третий пункт — практически каждый сайтовый движок, CMS, форум может генерировать РСС. Во многих движках есть ленты по отдельным авторам, тегам, комментариям к статьям, разделам форумов и даже поисковым запросам! Это же очень удобно — подписались на двух интересных авторов и читаете только их. Или отслеживаете комментации в интересной статье.
Четвертый — существет немыслимое количество приложений для чтения лент, для всех операционных систем и платформ. Читать можно в браузере, в десктоп-приложениях, в телефонах, планшетах. Немало сервисов основано на передачи данных из одного источника в другой именно в РСС-формате. Кросспост в Твиттер, Фейсбук и другие социальные сети основан на РСС-лентах. Сервис twitterfeed — абсолютный монополист в этой области — обслуживает на текущий момент свыше шести миллионов лент!
Пятый — в некоторые сайты помещают в ленту статьи целиком, а не только анонс. Если при этом в статье сохранены все теги, картинки и форматирование, то РСС-читалка становится полноценным браузером. Не нужно открывать сайт, загружать рекламу и баннеры.
Шестой — продвинутую читалку вроде Google Reader можно использовать как каталог избранных ссылок. На многих сайтах есть возможность помечать статью как избранную или добавлять в закладки (что по сути одно и то же). При этом они хранятся разрозненно: на Хабре — избранное только Хабра и т.д. Однако, если отмечать статьи в едином пространстве (в РСС-читалке), то поиск и просмотр избранных статей станет намного проще.
Представим, что РСС умер
Как теперь распростронять информацию с сайта, блога? Через Твиттер. Для того, чтобы организовать кросспост, владельцу сайта необходимо выполнить следующие шаги:
- зарегистрировать в Твиттере новое приложение;
- найти модуль для своей CMS или библиотеку для языка/платформы;
- все настроить, запустить, протестировать.
Хорошо, если сайт работает на какой-нибудь CMS вроде Дупала, Вордпресса или Джумлы. Для них модули уже есть. А как быть владельцам малораспространенных CMS или тем, чьи сайты работают на фреймворках или самописных движках? Уверены, что сможете все организовать сами? Действительно ли это проще, чем добавить ленту в twitterfeed?
Далее, при кросспосте нужно сокращать ссылки. Кто будет этим заниматься? Теперь ответственность лежит на вас. Регистрируемся в [Bit.ly]((http://Bit.ly), получаем открытый и закрытый ключи, качаем библиотеку для нужного языка, проходим OAuth-авторизацию и //только теперь// можем приступить к сокращению ссылок! Аналогично с Goo.gl: сперва включаем сервис в консоли API, получаем ключи, качаем библиотеки, читаем доки, авторизуемся и сокращаем. Уверяю, не все так просто. Тонкости работы с goo.gl я подробно описывал на Хабре.
Исходя из вышесказанного, можно с уверенностью предсказать возникновение сервисов, которые возьмут волокиту на себя. От нас только потребуется передавать информацию в удобном виде — вот заголовок, вот тело статьи, вот ссылка на оригинал. Формат, вероятно, XML — он лучше подходит для структурированных данных. И к чему мы пришли? Не к тому ли, что имеем — РСС и twitterfeed?
Не забываем, что размер твита ограничен 140 символами. Из них половина может уйти на заголовк статьи, плюс ссылка, плюс хэштеги и всё — упираемся в лимит. В итоге, полезность статьи можно оценить исключительно по заголовку, что, согласитесь, очень неудобно в сравнении с РСС.
И последний довод. Всю информацию, поступающую в Твиттер, можно разделить на два типа. Первый тип — то, что написано живыми людьми, неважно, при помощи какого приложения. Написал ли человек твит прямо на сайте, или отправил с телефона, или с Инстаграма — это первый тип. Такая информация отражает актуальные действия и мысли человека, т.е. прямо отвечает на вопрос-слоган «Что ты делаешь сейчас»?
Информация второго типа — та, что публикуется ботами и сервисами. В основном, это кросспост из блогов, новостных сайтов и сообществ вроде Хабра. Такая информация слабо привязана ко времени и имеет большую актуальность. Например, так ли важно, когда вы прочитаете новую техническую статью — спустя 10 минут, час или день после ее публикации?
Твиттер очень хорош для распространения актуальной информации первого типа. А со вторым типом он обращается плохо — информация тонет в сплошном потоке. Если ваш твит с ссылкой на статью не прочли в постоянно обновляемой ленте сейчас, то уже не прочтут никогда.
Твиттер не убил РСС-ленты, просто вытеснил их оттуда, где требуется скорость и актуальность. В остальном, РСС отлично справляются с задачей, заменить их нечем и не требуется.
Комментарии из старого блога
05/21/13 sheber: Отличный пост, спасибо. Кстати, Google Reader закрывается http://googlereader.blogspot.com/2013/03/powering-down-google-reader.html
-
Работаем с Твиттером
Как по-быстому связать приложение на Питоне с Твиттером?
Ответ — подключить библиотеку oauthtwitter.
Почему не python-twitter? Потому что первая гораздо меньше по объему кода и числу зависимостей от дополнительных модулей: 300 строк кода против 4000!
Установим необходимые библиотеки:
pip install ouath2 pip install httplib2 pip install simplejson
Для работы с Твиттером нужно зарегистрировать приложение. Твиттер позволяет указывать ссылки вида
localhost
или127.0.0.1
в поле «Callback URL», что очень полезно при разработке на локальной машине.Consumer key — это открытый ключ приложения, что-то вроде логина. Consumer secret — закрытый ключ, которым подписываются запросы к Твиттеру. Если вы где-то опубликовали его, немедленно смените в настройках приложения.
Авторизация в Твиттере проходит в несколько шагов.
Шаг 1: запрос на авторизацию
import oauthtwitter CONSUMER_KEY = "key" SECRET_KEY = "secret" # Инициализация клиента по ключам def sign_init(request): client = oauthtwitter.OAuthApi(CONSUMER_KEY, SECRET_KEY) # Уникальный токен, действительный только для одной авторизации request_token = client.getRequestToken() # Сохраняем токен в сессию пользователя. Можно сохранить на диск или в БД request.session["request_token"] = request_token # Получаем уникальный адрес авторизации на основе токена url = client.getAuthorizationURL(request_token) # Перенаправляем пользователя на страницу ввода пароля return redirect(url)
Шаг 2: ввод логина и пароля на стороне Твиттера
Шаг 3: возврат пользователя на ваш сайт
После авторизации пользователь будет направлен обратно на ваш сайт. Напомню, что в приложении на стадии тестирования у нас указано что-то вроде
http://localhost:8080/twitter/callback
По этому адресу должен быть обработчик, который завершит процесс авторизации.def sign_callback(request): # Извлекаем сохраненный ранее в сессии токен. # Если токена нет, то пусть начинает всё с начала. request_token = request.session.get("request_token") if not request_token: add_message(request, ERROR, u"Request token not found.") return redirect(frontpage) # Ключ валидации запроса из командной строки. oauth_verifier = request.GET.get("oauth_verifier") if not oauth_verifier: add_message(request, ERROR, u"OAuth verifier not found.") return redirect(frontpage) # Снова инициализируем клиента client = oauthtwitter.OAuthApi(CONSUMER_KEY, SECRET_KEY) # Извлечени параметров доступа access_token = client.getAccessToken(request_token, oauth_verifier) print access_token >>> { 'oauth_token_secret': 'xTbNbG0IcUGgng9pyNdy******************', 'user_id': '123123123', 'oauth_token': '78741204-cLgfThwKXuqudeXGTQP***********************', 'screen_name': 'username' }
Отлично! Как видно, access_token представляет из себя словарь со всеми нужными данными: идентификатором и именем пользователя, открытым и закрытым ключами доступа.
Дальнейший сценарий зависит от архитектуры вашего приложения. Например, на основании screen_name заводится новый пользователь (или извлекается имеющийся). Оба ключа записываются в профиль пользователя. Теперь можно работать с Твиттером:
# Инициализация клиента с ключами приложения и пользователя client = oauthtwitter.OAuthApi(CONSUMER_KEY, SECRET_KEY, user_oauth_token, user_oauth_token_secret) # Извлечение твитов пользователя timeline = client.GetUserTimeline() # Твитнуть сообщение client.UpdateStatus("Python testing") # Получить фолловеров timeline = client.GetFollowers()
И так далее, список всех методов ищите в коде класса. Очень доволен этой библиотекой, использую ее в двух проектах.
Комментарии из старого блога
02/11/13 Майя Любимая: я ничего не понимаю
02/20/13 Иван Гришаев: То же самое могу сказать о вашем комментарии.
-
Создание файлов Excel
В статье «Почему форматы Microsoft Office такие сложные?» Джоэл Спольски пишет:
Заставьте Office делать грязную работу за вас. Word и Excel завязаны на сложных объектных моделях, основанных на автоматизации COM, что позволяет программно делать всё, что угодно. Во многих ситуациях проще будет использовать код Office, чем пытаться реализовать его с нуля.
Действительно, если требуется сформировать сложный офисный документ, проще сделать это вызовами API через COM-соединение. Однако, для создания простой эксель-таблички можно задействовать библиотеку xlwt.
Библиотека ставиться просто:
pip install xlwt
Требуется сформировать таблицу с тремя колонками:
- номер лицевого счета абонента, строковый тип;
- дата показания, тип дата;
- показание, тип число.
Проект выполнен на Джанго. Есть модель показания, переданного абонентом:
class Statement(models.Model): user = models.ForeignKey(User) value = models.DecimalField(max_digits=12, decimal_places=6) date = models.DateTimeField(default=datetime.now)
Показания, которые необходимо записать в таблицу, извлекаются следующим образом
statements = Statement.objects.filter(date__range=(t1, t2))
Формирование файла Excel будет выглядеть так:
import xlwt # Определяем формат ячеек для дат date_style = xlwt.XFStyle() date_style.num_format_str = "M/D/YY" # Определяем формат ячеек для чисел num_style = xlwt.XFStyle() num_style.num_format_str = "0.00" wbk = xlwt.Workbook() # Новая книга sheet = wbk.add_sheet("statements") # Новый лист в книге # Добавляем шапку таблицы sheet.write(0, 0, u"Лицевой счет") sheet.write(0, 1, u"Дата") sheet.write(0, 2, u"Показание") # Обход показаний, statements — объект QuerySet из Джанго for i, s in enumerate(statements): # i — индекс итерации, используется как номер строки sheet.write(i+1, 0, s.user.username) sheet.write(i+1, 1, s.date, date_style) sheet.write(i+1, 2, s.value, num_style) # Задаем ширину колонок sheet.col(0).width = 5000 sheet.col(1).width = 5000 sheet.col(2).width = 5000 # Запись файла wbk.save("path/to/file.xls")
-
Запись непойманных исключений в файл
На работе у меня много скриптов, написанных на питоне, и большая часть из них выполняется ночью. Проблема — любой, даже самый надежный скрипт может упасть. Не удалось соединиться с БД, не найден нужный файл, отвалился сетевой ресурс, прислали кривой реестр.
Обрабатывать исключения на каждой операции — утомительно, код распухает на глазах. Гораздо важнее не отлавливать каждую ошибку, а фиксировать факт ее появления и ситуацию, в которой она возникла.
Модуль cgitb устанавливает свой обработчик на всплывающее исключение. Он пишет в файл всю необходимую информацию: дату, время, исключение, его параметры, имя скрипта, фрагмент кода, где было возбуждено исключение и локальные переменные.
Имея эти данные, нетрудно выявить причину ошибки и внести в скрипт нужные коррективы. Модуль очень полезен для CGI-скриптов: ошибки не придется искать в логах Апача, тем более, что такой подробной информации вы там не найдете.
Подключить обработчик очень легко:
import os import cgitb cgitb.enable(display=False, logdir=os.path.dirname(__file__))
logdir — директория, куда будет записан html-файл с информацией об ошибке. В данном примере указана директория, в которой расположен исполняемый скрипт. В CGI-скриптах должна быть указана директория, к которой нет публичного доступа.
При работе с cgitb важно подключать его как можно быстрее, желательно, в начале скрипта. Это поможет обработать ошибки импорта библиотек.
-
Работа с файлами mailbox
Чем хорош почтовый клиент Mozilla Thunderbird?
Хотя бы тем, что хранит письма в удобном формате mailbox. Благодрая этому можно рулить почтой программно: считывать содержимое ящика, удалять и добавлять письма.
Зачем это может понадобитсья? Например, каждый день вам на почту приходят реестры платежей, которые нужно выгрузить из аттача, распаковать, и, в зависимости от имени файла, скопировать в определенную директорию. Напрашивается автоматизация процесса.
В составе богатой библиотеки Питона есть модуль mailbox. Небольшой пример:
import os import cgitb cgitb.enable(display=False, logdir=os.path.dirname(__file__)) import mailbox MAILBOX_PATH = "path/to/mailbox.file" # Путь к файлу ящика DATA_PATH = "store/path" # Директория для файлов mbox = mailbox.mbox(MAILBOX_PATH, create=False) for i, message in enumerate(mbox): attachments = message.get_payload() for attachment in attachments: filename = attachment.get_filename() if filename and filename.endswith(".txt"): body = attachment.get_payload(decode=True) filepath = os.path.join(DATA_PATH, filename) with open(filepath, "w") as f: f.write(body) mbox.remove(i) mbox.close()
Основной цикл обходит все письма в ящике. Переменная attachments — это список частей письма. Частью может быть всё — простой текст, HTML-сообщение, файловое вложение и т.д.
get_filename()
возвращает имя части. Для файлов оно будет отлично от None. Нас интересуют только текстовые файлы. Тело файла извлекается методомget_payload()
части.При передаче файла он может быть закодирован методами base64 или uuencode. Чтобы получить исходный файл, передается параметр
decode=True
. Полученный файл пишется на диск.Сообщение удаляется из ящика. По окончании цикла ящик закрывается.
-
Рассылка смс в Питоне
Отправлять короткие сообщения можно с помощью любого из многочисленных сервисов смс-рассылок.
Я остановил свой выбор на LittleSMS. Низкая фиксированная цена, удобные API, подробная документация, готовые решения для многих языков и платформ.
Работа с сервисом осуществляется по протоколу HTTP GET-запросами. При регистрации вы получите API-ключ. Этим ключом подписываются все запросы. Ключ не является паролем к учетной записи. Если ключ где-то засветился, немедленно смените его в личном кабинете сервиса.
Для Питона рекомендую использовать мою библиотеку с Гитхаба.
Пример работы:
import littlesms # Инициализация класса api = littlesms.Api("user", "API_key") # Проверка баланса. print api.balance() >>> {u'status': u'success', u'balance': 0.5} # Отправка сообщения. print api.send(u"Hello, World!", "7xxxxxxxxxx") >>> { u'count': 1, u'status': u'success', u'recipients': [u'7xxxxxxxxxx'], u'price': 0.5, u'parts': 1, u'test': 0, u'balance': 0.5, u'messages_id': [u'xxxxxx'] } # Отправка сообщения нескольким адресатам с подменой поля «отправитель». recipients = ("7xxxxxxxxx1", "7xxxxxxxxx2", "7xxxxxxxxx3") print api.send(u"Hello, World!", recipients, sender="Anonym") >>> { u'count': 1, u'status': u'success', u'recipients': [u'7xxxxxxxxx1', u'7xxxxxxxxx2', u'7xxxxxxxxx3'], u'price': 0.5, u'parts': 1, u'test': 0, u'balance': 0.5, u'messages_id': [u'xxxxxx1', u'xxxxxx2', u'xxxxxx3'] } # Если компьютер расположен за прокси со сложной схемой авторизации. PROXY = { "proxy": "172.27.86.8", "port": 3128, "user": "ivan", "passw": "secret" } opener = littlesms.curl_opener(**PROXY) api = littlesms.Api("user", "API_key", opener=opener) # Пример работы в облачной платформе App Engine. opener = littlesms.gae_opener() api = littlesms.Api("user", "API_key", opener=opener) # Пример обработки исключения. try: print api.send(u"Hello, World!", "7xxxxxxxxxx", sender="TooLongSender!!!111") except littlesms.ApiError, e: print e >>> Error 7: incorrect sender
Библиотека активно используется больше года в проекте личного кабинета Читинской энергосбытовой компании. На текущий момент отправлено около 15000 сообщений.