xmlhack.ru logo
>> статьи на xmlhack.ru

Написание скриптов для Flickr на Python и REST

Автор: Юч Огбуджи
Перевод: эгеши
Опубликовано на XML.com (25.01.2006, англ.): http://www.xml.com/pub/a/2006/01/25/scripting-flickr-with-python-and-rest.html
Опубликовано на xmlhack.ru (13.02.2006, рус.): http://xmlhack.ru/texts/06/scripting-flickr/scripting-flickr.html
В закладки:   Del.icio.us   reddit

Тем, что читает эту статью, наверное, не нужно представлять Flickr. Это прекрасно известный веб-сайт, владельцем которого авляется Yahoo, и который, в первую очередь, предназначен для обмена фотографиями. В сайт включено множество современных инструментов, названия которых у всех на слуху: tagging, web feeds, AJAX и инструменты доступности скриптов. Flickr предоставляет набор API's, основанных на HTTP, для доступа к функциям публикации и просмотра изображений. У вас есть возможность выбора между XML-RPC, REST (упрощённый XML по HTTP) или SOAP, не считая основных функций, которые позволяют использовать сервис Flickr так, как вам нужно. В этой статье я расскажу про некоторые библиотеки Python, предназначенные для интеграции с Flickr (код проверен для Python 2.4.2.).

Первое, что вы заметите в примерах, — это ключ для Flickr API. Этот ключ всегда необходим для доступа к Flickr через официальный API, и если вы хотите получить доступ к возможностям написания скриптов, вам необходимо поучить ключ на странице ключей Flickr API. Flickr использует систему доступа, основанную на вашем ключе. Система полностью описана на странице Flickr Authentication API Desktop Applications How-To. Если вы хотите узнать всю подноготную аутентификации Flickr, обязательно прочтите эту страницу. Библиотеки Flickr позволяют вам абстрагироваться от большей части этих мелочей, однако в этой статье я буду использовать действия, которые не требуют особенной или специальной авторизации. Обязательно просмотрите домашнюю страницу Flickr API. На ней содержится документация, ссылки на примеры использования для любого популярного языка программирования за исключением C/C++ и JavaScript.

FlickrClient

Пионером в создании инстументов для Flickr является Мишель Кампеотто (Michele Campeotto), работа которого позволила создать библиотеки, о которых мы будем говорить далее. В первую очередь он известен по пакету FlickrUploadr, программы, которая предоставляет простой пользовательский интерфейс (GIU), используя набор GTK для Linux. Пользователь перетаскивает изображения в обычное окно, из которого картинки могут быть загружены непосредственно в аккаунт на Flickr. FlickrUpload в основном предназначен для конечных пользователей, так что я не буду более рассказывать о его возможностях. К теме данной статьи более близок FlickrClient — библиотека, созданная Кампеотто для Flickr. Я установил FlickrClient, скопировав два файла Python из пакета на сайте в мои пакеты Python. Один из этих файлов — xmltramp, простой Python API, созданный Аароном Шварцем (Aaron Swartz), позволяет видеть древовидную структуру XML. Листинг 1 представляет собой простой пример, отображающий получение всех общедоступных изображений пользователя Flickr с именем “uche”. Переменная FLICKR_API_KEY в этом и других листингах должна быть изменена на ваш ключ API.

Листинг 1: Использование FlickrClient для получения названий избранных изображенй


>>> from FlickrClient import FlickrClient
>>> client = FlickrClient(FLICKR_API_KEY)
>>> #Find the user ID of the person named "uche"
>>> person =
client.flickr_people_findByUsername(username='uche')
>>> import pprint
>>> pprint.pprint(person.__dict__)
{'_attrs': {u'id': u'21902936@N00', u'nsid': u'21902936@N00'},
 '_dNS': None,
 '_dir': [<username>...</username>],
 '_name': u'user',
 '_prefixes': {}}
>>> userid = person(u'id')
>>> print userid
21902936@N00
>>> faves =
client.flickr_favorites_getPublicList(user_id=userid)
>>> faves[0]
<photo isfamily="1" title="P1010024" isfriend="1" ispublic="1"
server="30"
secret="c68a340791" owner="75062596@N00"
id="63291069"></photo>
>>> for fave in faves:
...     print fave(u'title')
...
P1010024
Ãfrica...
AFRICAN DREAM
Goro
In Concert
Fela Anikulapo Kuti
Heaven's Light on Lake Malawi
>>>

Flickr документирует запросы API в форме flickr.people.findByUsername. Вы заменяете точки на подчёркивания в FlickrClient и вызываете результирующий метод на объекте Flickr proxy object (client в листинге 1). FlickrClient отправляет запрос на Flickr. На самом деле Flickr API не содержится в коде FlickrClient (в нём всего-то 40 строк кода). Практически всегда вам нужно предоставить как минимум один параметр для Flickr. Вы должны предоставлять их как ключевые слова (например, username="uche"). для того, чтобы всё работало. Вы можете найти названия параметров в документации к Flickr. Если вы отправляете ошибочные аргументы, то несомненно заметите ошибочный ответ, но к счастью, API очень прост в освоении, так что скоро вы избавитесь от этого. В ответ вы получите результат работы xmltramp — узлы, представляющие XML-ответ Flickr, и с этого момента вы можете получать доступ к нужным данным. Как показано в Листинге 1, я использовал __dict__ и repr() для просмотра результатов, после чего я точно знаю, где взять данные, которые мне необходимы. Некоторые запросы возвращают список, который приходит как контейнерный элемент со множественными дочерними нодами как в случае с flickr.favorites.getPublicList.

Как я заметил выше, я использую запросы Flickr, не требующие авторизации. Как пример того, что требует авторизации, можно привести flickr.favorites.getList, который получает все избранные изображения, в том числе и частные (private). Если вам необходимо использовать возможности Flickr, требующие авторизации, вам потребуется сначала направить пользователя на страницу, где он сможет ввести логин и получть ваши пользовательские привилегии на Flickr. Затем вам нужно запросить Flickr снова для получения в результате маркёра, подтверждающего авторизацию. Это немного запутанный процесс и ниже я опишу инструмент FlickrClient-derived, который совершает соединение автоматически. Вы сможете получит из него необходимую часть кода даже если используете FlickrClient.

flickrlib

FlickrClient использует REST API, запрашивая простые URL с Flickr через HTTP GET (даже в тех случаях, когда должен быть использован HTTP POST, но пусть вас это сильно не грузит) и возвращает XML-ответ. Это очень простая и гибкая система. Этан Айзексон (Eitan Isaacson) предпочитает использовать стандартную библиотеку Python XML-RPC, поэтому он написал flickrlib. Я скачал версию пакета 0.5. Установка — стандарная, distutils python setup.py install, однако всё, что она делает — это копирует единственный файл flickrlib.py в вашу библиотеку Python. Листинг 2 — это попытка отображения запросов Листинга 1. Главное, что вы могли заметить — это названия методов, точно такие же, как и в спецификации Flickr API, также отпадает необходимость конвертации точек в подчёркивания. Переменная FLICKR_API_SSECRET должна быть установлена в отдельное значение, известное только вам.

Листинг 2: Interactive session using flickrlib to get a list of favorite photo titles


>>> import flickrlib
>>> client = flickrlib.FlickrAgent(FLICKR_API_KEY,
FLICKR_API_SSECRET)
>>> #Find the user ID of the person named "uche"
>>> person =
client.flickr.people.findByUsername(username='uche')
>>> person
{u'username': [{u'text': u'Uche', u'type': u'username'}],
 u'text': u'', u'type': u'user', u'id': u'21902936@N00',
 u'nsid': u'21902936@N00'}
>>> userid = person[u'id']
>>> faves =
client.flickr.favorites.getPublicList(user_id=userid)
[SNIP]
UnicodeEncodeError: 'ascii' codec can't encode character u'\xc1' in
position 270: ordinal not in range(128)

Ошибка получена из-за того, что в именах моих файлов были символы, не входящие в таблицу ASCII. flickrlib сейчас не поддерживает эту возможность. В листинге 3 я попробовал составить другой запрос с ответом, который был бы похож на список.

Листинг 3: Интерактивная сессия с использованием flickrlib для получения информации об изображении


>>> import flickrlib
>>> client = flickrlib.FlickrAgent(FLICKR_API_KEY,
FLICKR_API_SSECRET)
>>> #Find the user ID of the person named "uche"
>>> person =
client.flickr.people.findByUsername(username='uche')
>>> userid = person[u'id']
>>> #Get the first 10 photos for the user
>>> photos =
client.flickr.people.getPublicPhotos(user_id=userid, per_page=10)
>>> photos.keys()
[u'perpage', u'text', u'page', u'photo', u'total', u'type',
u'pages']
>>> photo = photos[u'photo'][0]
>>> photo[u'title']
u'IMG_1223'
>>> photoinfo =
client.flickr.photos.getInfo(photo_id=photo[u'id'],
                                            
secret=photo[u'secret'])
>>> for tag in photoinfo[u'tags'][0][u'tag']: print
tag[u'text']
...
friends
family
>>>

flickrlib превращает ответы XML-RPC в структуру данных в виде словарей и списков. Лучший способ понять, как добраться до того, что вам нужно, полностью доступен в документации по Flickr API. Например, flickr.photos.getInfo:


<photo id="2733" secret="123456" server="12"
  isfavorite="0" license="3" rotation="90" originalformat="png">
[SNIP]
  <tags>
    <tag id="1234" author="12037949754@N01" raw="woo
yay">wooyay</tag>
    <tag id="1235" author="12037949754@N01"
raw="hoopla">hoopla</tag>
  </tags>
[SNIP]
</photo>

Из этого примера ясно, как получить исходный формат изображения, используя response[u'originalformat'], список тэгов response[u'tags'][0] (первый дочерний элемент под названием tags), текст первого тэга из response[u'tags'][0][u'tag'][0][u'text'], и так далее. Атрибуты XML обычно доступны как ключи словаря и дочерние элементы XML — как элементы списка.

Не забывайте про предупреждение Этана:

Библиотека не поддерживает класс ошибок и небезопасна при использовании потоков и поэтому она просто сойдёт с ума, если вы не установите мутекс-локи (mutex lock) на запросы к этой библиотеке.

Честно говоря, все библиотеки Python для Flickr, которые я знаю, содержат достаточно таких штук, которым разработчику необходимо уделять внимание.

flickr.py

Я показывал как Flickr API возврашает низкоуровневые структуры данных или «сырой» XML, которые должен разделить разработчик. Достоинство — это простой код библиотеки, в то же время клиентский код должен быть более сложным. Джеймс Кларк (James Clarke) решил упростить результаты, принимаемые от Flickr, и написал flickr.py. Я скачал файл Python (rev. 24) и скопировал его в библиотеку Python вручную. Обратите внимание, как я устанавливаю ключ API непосредственно в модуле.

Листинг 4: Интерактивная сессия с использованием flickr.py для получения информации об изображении


>>> import flickr
>>> flickr.API_KEY = FLICKR_API_KEY
>>> user = flickr.people_findByUsername(u'uche')
>>> user.id
u'21902936@N00'
>>> photos = flickr.photos_search(user_id=user.id)
>>> for tag in photos[0].tags: tag.text
...
u'friends'
u'family'
>>> faves =
flickr.favorites_getPublicList(user_id=user.id)
>>> for fave in faves: print fave.title
...
P1010024
Ãfrica...
AFRICAN DREAM
Goro
In Concert
Fela Anikulapo Kuti
Heaven's Light on Lake Malawi
>>>

Сразу заметно, насколько простым и ясным стал API. Проблема лишь в том, что он требует работы flickr.py, но воплощён пока что не весь Flickr API. Вы можете посмотреть документацию модуля ( help(flickr)) насчёт информации о том, что ещё не включено. Также необходимо заметить, что названия функций полностью отличаются от названий методов Flickr, так что вам придётся рассчитывать, скорее всего, на документацию к flickr.py, нежели на документацию по собственно Flickr API.

Beej's Python Flickr API

Бидж Йоргенсен (Beej Jorgensen) собрал простую библиотеку Python с поддержкой Flickr API, котрая называется flickapi.py. Он взял немного кода и придумал пару велосипедов, однако создал имплементацию узлов XML прямиком в центральном модуле. Он говорит, что это было просто упражнение, однако я думаю что мотивацией на самом деле было желание избежать зависимости от третьестороннего кода. Во всяком случае, библиотека состоит из 200 строк кода, и я не буду углубляться в дизайн кода. Более важным является то, что, что я так и не смог заставить её толком работать. Листинг 5 показывает мои продвижения в этой области.

Листинг 5: Образец интерактивной сессии с попыткой использования flickrapi.py


>>> from flickrapi import FlickrAPI
>>> #initialize a proxy instance for the Flickr API and
get a session token
>>> fapi = FlickrAPI(FLICKR_API_KEY, FLICKR_API_SSECRET)
>>> fapi = FlickrAPI(FLICKR_API_KEY, FLICKR_API_SSECRET)
>>> token = fapi.getToken(perms='write',
browser='firefox')
rsp: error 108: Invalid frob

Последняя строка должна получать маркёр (token) от Flickr и запускать сессию, чтобы конечный юзер мог получить доступ к Flickr и создать разрешения для приложения, чтобы оно могло действовать как агент пользователя. К сожалению, как я ни крутил-вертел разрешения, броузер, изпользуемый для запросов, я получал только ошибку “Invalid frob”.

Обложка

Ещё один код для Python, предназначенный для конечных пользователей — uploadr (автор — C.Mallory). Код загружает на сервер все изображения из выбранной директории, если они ещё не там (не на Flickr).

Всегда неплохо иметь выбор, и он есть, если вам необходимо получит доступ к Flickr с кодом Python. Разные библиотеки отражают разные философии и вы всегда сможете найти то, что вам необходимо.

Попробуйте взглянуть на страницу изображений с тэгами Python на Flickr. Я надеюсь, что из-за популярности сервиса среди разных программистов, там появится что-то кроме фотографий змей. Однако реальность, видимо, опровергает мои предположения. С другой стороны, поиск в Google по запросу “python” выдаёт ссылки только на язык программирования и комедию Монти Пайтон. Этот интересный эффект наблюдается вне зависимости от того, используете ли вы семантический поиск или нет.



XML.com Copyright © 1998-2007 O'Reilly Media, Inc.
Перевод: xmlhack.ru Copyright © 2000-2007 xmlhack.ru