Журнал LinuxFormat - перейти на главную

LXF124:Python

Материал из Linuxformat
Перейти к: навигация, поиск
Python Заставим Web доставлять нужное содержимое вам на блюдечке

Содержание

Python: Загрузчик во Flickr

Наши уроки Python доросли до графического интерфейса, и сегодня Ник Вейч научит вас выгружать изображения с рабочего стола прямо в Web.

Много событий системных часов тому назад было решено, что для пассивных-то посетителей Интернет хорош, но людям нужно большее. Итак, вместо того чтобы сделать коллективную мудрость привилегией тех избранных, что содержат web-сайты, решили дать права записи в Web всем желающим. Chmod ugo+rwx -R http://*, если хотите – реально опасная штука. Тут и стало практически невозможно получить толковый результат при вводе чего бы то ни было в Google: родился самопубликующийся Web.

На протяжении всей серии уроков мы, преимущественно, работали на сбор данных из сети и подчинении их нашей злой воле. Однако на сей раз мы вознаградим сеть в ответ. Облако нам вполне подойдет, и мы скормим ему несколько фотографий.

Мы подметили, что консоль – трудно познаваемый способ работы в сети. Фанатики, вероятно, сочтут кощунством извлечение какой бы то ни было пользы кем попало, не изучившим наборов переключателей командной строки с тремя уровнями вложения, но мы милосердно перебросим мост через пропасть, создав графический интерфейс пользователя (GUI).

Flickr API и вы

Flickr – не просто загрузка картинок. Ну и не только стеб над фотографиями ваших друзей (или, еще лучше, на фотографиями незнакомцев). На самом деле, благодаря сведениям Exif, тэгам и множеству других типов данных, Flickr является прекрасной площадкой для создания приложений. Мы рассмотрим это в последующих выпусках серии для некоторых программно созданных изображений, и проекта, помещающего данные из Flickr на карту. Один из главных плюсов API Flickr – отличная онлайн-документация. Наряду с описанием каждого вызова, здесь содержится множество примеров, позволяющих даже испытать различные функции через web-формы. Ознакомьтесь и проникнитесь на http://www.flickr.com/services/api.

Python на рабочем столе

Нашему настольному приложению необходимо тесно интегрироваться с базовой системой. При выборе среды пользователи Gnome задавили числом, и для создания GUI мы взяли GTK. Если у вас KDE – сочувствую вашему горю. Зато выбранный подход имеет небольшое преимущество: мои эксперименты показали, что решение с GTK требует на пару строк меньше кода, чем с KDE/Qt. А если вы пожелаете перенести программу на wxWidgets, это не станет проблемой, когда вы поймете ее функции. Однако, прежде тем, как двигаться дальше, заполучите PyGTK от вашего менеджера пакетов.

Ранее мы создавали сценарии строку за строкой в интерактивной оболочке Python, но при написании графического приложения все становится сложнее, потому что такие программы менее линейны. По сути, мы переходим от скриптописания к созданию объектно-ориентированных приложений. О том, что такое объектно-ориентированное программирование (ООП), идет много споров, но мы имеем в виду – по крайней мере здесь – что мы создадим объект, выполняющий действия при определенных условиях. Если мы не будем ничего делать с объектом, он не будет ничего делать для нас. А в ответ на наш вызов он сделает то, что мы скажем – если попросить хорошенько.

В нашем первом примере вам следует набрать текст в любимом редакторе (или, кхе, скопировать из каталога на DVD), а не вводить строку за строкой в интерпретаторе. Так тоже можно, но мы вам этого не советуем, потому что мы воспользуемся множеством методов, которые не будут вызываться до самого конца, и допущенную ошибку будет трудновато обнаружить.

Наш первый объект – просто окно приложения, появляющееся на рабочем столе. Большую часть времени оно только и делает, что сидит себе окном. Но стоит вам перетащить в него файл, как оно выдаст вам его имя и путь к нему – первый шаг к созданию нашего клиента Flickr типа сделай-сам. Для этого потребуется загрузить соответствующие модули, создать метод для вывода имени файла на экран и написать GTK-приложение. Вот получившийся код – загрузите и запустите его:


 import pygtk
 import gtk
 def rec_cb(widg, context, x, y, selection, info, time):
  #получаем корректный объект
  filename= selection.data[7:-2]
  print filename
  l.set_text(filename)
 #gtk app-building magic
 w = gtk.Window()
 w.set_size_request(200, 200)
 w.drag_dest_set( gtk.DEST_DEFAULT_MOTION | \
    gtk.DEST_DEFAULT_HIGHLIGHT |\
    gtk.DEST_DEFAULT_DROP \
    ,[(“UTF8_STRING”, 0, 0 )], \
    gtk.gdk.ACTION_COPY)
 w.connect(‘drag_data_received’, rec_cb)
 w.connect(‘destroy’, lambda w: gtk.main_quit())
 l = gtk.Label()
 w.add(l)
 w.show_all()
 gtk.main()

На первый взгляд это выглядит колдовством, но лишь потому, что невидима большая часть кода, заставляющего все это работать. Еще до объяснений, давайте все проверим: запустите код, и откроется окно. Перенесите в него файл с рабочего стола. Теперь отпустите файл – и увидите его имя.

Взгляните на блок-схему справа. Великие умы создали ее, чтобы вы лучше поняли процесс. Окно задано как пункт назначения события Drag’n’Drop, и когда в область окна что-то бросают, приложение вызывает соответствующую процедуру. На диаграмме также видна штриховая линия. Единственная часть кода, которую вы должны написать (кроме еще пары строк настройки) – то, что расположено ниже нее; об остальном позаботится платформа GTK.

Ресурсы GTK

Вам будет проще, если до попытки изучать PyGTK вы поймете механику GTK. Правда, все примеры на C, а не на Python, но разнообразие базового материала всегда полезно.

На http://www.pygtk.org/pygtk2tutorial имеется хорошо написанное руководство по PyGTK, хотя и немного устаревшее. Более общее введение можно поискать в Gnome/GTK, и нам показалось, что Official Gnome 2 Developer’s Guide – довольное приятное чтение (поищите ISBN:978-1593270308).

Если вы желаете облегчить создание интерфейса (поплатившись малопонятностью для вас сгенерированного кода), установите Glade и поиграйте со всеми виджетами.

Распутываем код

Пока проигнорируем описание функции и перейдем к строке, начинающейся с w = gtk.Window(). В ней создается объект-окно нашего приложения. Следующая строка – самая важная и, возможно, самая темная. Здесь мы разбили ее (используя маркер продолжения строки Python \) на части, чтобы вы могли увидеть, что окно вызывает метод drag_dest_set с тремя параметрами. Первый – некий набор флагов, говорящий GTK, как это окно себя ведет. Использование флага DEFAULT_MOTION означает, что мы не хотим отслеживать перемещение курсора самостоятельно (нас устраивают стандартные проверки). Флаг DEFAULT_HIGHLIGHT сообщает, что GTK автоматически подсветит область бросания, если над ней окажется подходящий объект, а благодаря флагу DEFAULT_DROP брошенный объект с желаемым типом данных автоматически будет принят с генерацией сигнала drag_data_received. Можете определить собственные методы для управления большинством таких событий, но особого смысла в этом нет.

Следующий передаваемый параметр – список кортежей. У нас в списке кортеж только один. Каждый кортеж указывает принимаемый тип данных – в нашем случае UTF8_STRING: сначала строка, содержащая тип, несколько флагов, способных запретить вам использовать данные одного и того же приложения или структуры виджетов, и идентификатор. Идентификатор полезен в случае приема данных большого числа типов. Последний передаваемый параметр – тип разрешенного действия, опять-таки с флагом, определенным в GTK-модуле. В данном случае мы используем флаг для действия «копирование», иначе исходные данные уничтожатся после того, как вы отпустите файл в окне.

Так откуда же взялось это UTF8_STRING? Невидимая для вас часть кода – это сам рабочий стол. Gnome сам постоянно пользуется функциями Drag’n’Drop GTK, в основном при размещении файлов в каталогах. То есть иконки вашего рабочего стола уже настроены как источники операций Drag’n’Drop и обладают набором доступных типов пункта назначения. Если вы хотите посмотреть их, измените код, вместо l.set_text(filename) подставив

l.set_text(‘\n’.join([str(t) for t in context.targets]))

Выведется список доступных типов пунктов назначений, и вы увидите, как много вариаций на эту тему. Мы используем формат UTF8, потому что будем захватывать имя файла объекта для дальнейшего употребления, а Python любит UTF-строки.

Итак, мы настроили механику того, что будет принимать окно. Следующая строка соединяет сигнал drag_data_received и метод rec_cb, определенный нами ранее. Мы настроили сигнал в предыдущей строке, так что он генерируется GTK, когда что-то бросают в наше окно. Если мы не соединим их, то ничего происходить не будет.

Следующая строка настраивает выход из программы по сигналу destroy, который генерируется при щелчке пользователя на кнопке закрытия окна. Затем мы добавляем виджет Label [метка] (для отображения текста) и вызываем метод show_all() для нашего окна, что делает его и все дочерние элементы видимыми. Однако оно не отобразится, пока не будет запущен главный цикл приложения, а это уже следующая строка. По вызову gtk.main() контроль над вашей программой передается GTK. Все дальнейшие действия – отрисовка окна при перемещении, изменении размера, закрытие и так далее – выполняются кодом GTK, кроме функции, которую мы прикрепили к нашему сигналу data received. Этот способ известен как обратный вызов, поскольку он вызывается основным приложением в ответ на некоторое событие – в нашем случае, сигнал.

Теперь код прояснился. Генерируемый для события сигнал снабжается информацией, большая часть которой нам не интересна. Однако мы имеем дескриптор виджета, получившего сигнал, контекст и данные о расположении, само выделение, тип его данных (согласно его ID), а также время возникновения. Получаемые данные являются элементом выделенного передаваемого объекта, и мы можем извлечь их и отсечь первые семь и последние два символа, содержащие file:// и маркер конца строки. Останется путь, и мы используем его для записи данных в метку нашего окна, вызвав соответствующий метод для объекта-метки, l.

Другие GUI

Python не ограничен использованием GTK – на самом деле имеется уйма привязок к графическим инструментариям. В частности, рекомендуем в качестве альтернативы PyQt/PyKDE, особенно если вы желаете взаимодействовать с рабочим столом KDE. PyKDE весьма схож с PyQt, хотя есть и отличия. KDE широко использует инструментарий Qt, но все его объекты и методы образуют дополнительный KDE-слой, потому и существуют PyKDE (для приложений KDE) и PyQt (для стандартных приложений Qt).

Альтернатива – wxWidgets. Не говоря о простоте и легкости использования, основным источником славы wxWidgets является кроссплатформенность, благодаря библиотекам, привязанным к родным инструментариям. Поэтому приложения wxWidgets, запущенные в Linux, выглядят как программы Gnome/GTK, в Windows – как стандартные приложения Windows, а в Mac используются родные интерфейсы Aqua, Cocoa, Carbon.

Внедрим в жизнь данные

Объяснение кода GUI заняло много места, но если вы хотите разрабатывать подобные программы, то важно понимать его и не считать его магией. Итак, у нас есть имя файла, и с ним можно что-то сделать. Для выгрузки файла во Flickr потребуется некоторая подготовка. Во-первых, получите учетную запись на www.flickr.com – если она у вас уже есть, то войдите. Во-вторых, понадобится ключ API и секретная комбинация, которую вы можете получить, зарегистрировав свой скрипт как некоммерческий пользователь API на http://www.flickr.com/services/api/keys/apply. Теперь необходимо получить для приложения жетон (токен) на доступ к указанной учетной записи. Вот как приложение входит на Flickr:

 >>> import flickrapi
 >>> api_secret=’xxxxваш_секретxxxx’
 >>> api_key=’yyyyyyваш_ключyyyyyy’
 >>> flickr=flickrapi.FlickrAPI(api_key,api_secret)
 >>> (token,frob)= flickr.get_token_part_one(perms=’write’)
 >>> flickr.get_token_part_two((token, frob))u’7215780808080-a94e70effffeebb01’

Когда вы достигаете предпоследней строки, происходит странная штука: ваш стандартный браузер открывается на странице Flickr. Здесь вы должны войти и ответить на несколько вопросов, чтобы позволить приложению входить на Flickr от вашего имени. Не забудьте набрать последнюю строку, поскольку она дает токен, связывающий учетную запись Flickr и это приложение. Мы используем токен, чтобы наше приложение могло войти на сервер за вас, но вы, если хотите, можете выполнить авторизацию внутри программы. По умолчанию модуль flickrapi в любом случае кэширует токены, и вам придется авторизоваться только один раз, хотя в настройках можно и запретить сохранение токена. Но нам-то токен как раз пригодится, во избежание генерации дополнительного кода.

Пора и выгрузить что-нибудь! Объект flickr, который мы взяли из модуля, содержит метод загрузки изображений. Вот полный список принимаемых им параметров:

  • filename Имя файла изображения. Единственный обязательный параметр.
  • title Название фотографии.
  • description Текст описания.
  • tags Строка со списком тэгов, разделенных пробелом.
  • is_public Содержит 1, если фотография публичная, 0 – если частная. По умолчанию – публичная.
  • is_family Содержит 1, если фотография видна членам семьи, 0 – если нет. По умолчанию – не видна.
  • is_friend Содержит 1, если фотография видна друзьям, 0 – если нет. По умолчанию – не видна.
  • callback Метод, получающий два параметра: progress и done.
  • format Формат отклика.

На наше счастье, действительно необходимо из этого только имя файла; остальные параметры не обязательны и могут быть переданы по методу ключ=значение следующим образом:

MyFlickrObject.upload(filename=’/home/evilnick/plop.jpg’, tags=’plop image jpeg’, title=’This is Plop!”)

Мы не должны задавать все параметры или даже помнить их порядок – все может быть проще. Если вы пользуетесь Flickr, то, вероятно, уже хорошо знакомы с тэгами и правами доступа.

Дополнительного объяснения требуют разве что опции callback и format. format нужна только для того, чтобы сообщить серверу Flickr, как отформатировать выводимые данные. О ней можно вообще забыть, потому что модуль Python позаботится о приведении отклика к подходящему виду. А вот callback полезен. Он позволяет сослаться на метод в вашем коде, получающий информацию от процесса выгрузки (upload), сообщая вам о ходе загрузки, и меняет значение флага по ее завершении Если мы хотим предоставить пользователям нашего приложения некую обратную связь, он очень пригодится.


Итак, с небольшими исправлениями, чтобы заработала загрузка, наш код будет выглядеть так:

 import pygtk, gtk, flickrapi
 api_key=’----ваш-ключ--- ’
 api_secret=’----ваш-секрет----’
 api_token=’----ваш-жетон----’
 flickr = flickrapi.FlickrAPI(api_key, api_secret, token=api_token)
 def rec_cb(wid, context, x, y, selection, info, time):
   filename= selection.data[7:-2]
   flickr.upload(filename=filename, is_public=0)
   x=gtk.MessageDialog(parent=w, flags=gtk.DIALOG_MODAL, type=gtk.MESSAGE_INFO,
   buttons=gtk.BUTTONS_OK, message_format=’file was uploaded’)
   x.show_all()
 #gtk app-building magic
 w = gtk.Window()
 w.set_size_request(200, 200)
 w.drag_dest_set( gtk.DEST_DEFAULT_MOTION | \
    gtk.DEST_DEFAULT_HIGHLIGHT |\
    gtk.DEST_DEFAULT_DROP \
    , [(“UTF8_STRING”, 0, 0 )], \
    gtk.gdk.ACTION_COPY)
 w.connect(‘drag_data_received’, rec_cb)
 w.connect(‘destroy’, lambda w: gtk.main_quit())
 l = gtk.Label()
 w.add(l)
 w.show_all()
 gtk.main()

Мы можем видеть, что кроме некоторого кода настройки, нам осталось сделать единственный кусочек работы с Flickr: вызов метода upload в обработчике события Drag’n’Drop. Чтобы сообщить пользователю об успехе загрузки, мы открываем модальный диалог с соответствующим сообщением.

Итак, хотя оно не пройдет тест на удобство использования, оно у вас есть – настольный загрузчик изображений по технологии Drag'n'Drop в менее 30 строк кода. Выходит, программирование GUI не так уж и сложно?

Идем дальше

Если вы хотите расширить это приложение, то весьма легко добавить всевозможные флажки для настройки приватности, или виджет для ввода текста, чтобы получать заголовок, описание или тэги. Честолюбцы могут замахнуться на размещение в области бросания миниатюр изображений, а также добавить индикатор прогресса, через обратный вызов из метода flickr.upload() для его обновления. Однако все эти улучшения требуют знания GTK и PyGTK, так что обратитесь за подробной информацией к разделу Ресурсы GTK.

Итак, сегодня мы научились добавлять к нашим web-поделкам взаимодействие с пользователем, что делает некоторые из наших мэшап-проектов проще в использовании. А раз так, стоит немного и поизучать PyGTK и его виджеты.

Больше Flickr

Flickr – столь ценный источник данных, что мы не можем и дальше оставлять его неизученным. Сегодня мы резвились с основами выкладывания файлов в сервис, но во всех этих мегапикселях так много способов программно изучить накопленные художественные шедевры! Короче, мы скоро вернемся к Flickr для создания экспресс-карт.

LXF

Персональные инструменты
купить
подписаться
Яндекс.Метрика