LXF123:Python
|
|
|
- Python Заставим Web доставлять нужное содержимое вам на блюдечке
Содержание |
Python: Роемся в XML
- Часть 4: Мы вскроем API Сети посредством XML. Ваш отважный проводник по глубинам Python, Ник Вейч, не успокоился, пока не откопал Digg.
Ранее в этом цикле статей в качестве интерфейса для наших web-объектов и работы с ними мы использовали существующий API-код. Это экономит кучу времени, но иногда и ограничивает, делая нас зависимыми от других. И вообще, зачем беспокоиться о импорте целого модуля API, если требуется всего несколько методов?
Итак, на сей раз, невзирая на то, что есть весьма удачные API для Digg – хотя и слегка несвежие – мы создадим вместо них свой собственный. Ну, типа того. Мы не собираемся охватывать всю функциональность Digg, но освоим достаточно, чтобы при желании вы смогли создать полноценный API.
Многие сайты используют конкретный способ взаимодействия со своими API, а некоторые – даже несколько способов. Самые популярные – JSON и XML. JSON проще и легко интегрируется с JavaScript, поэтому встречается часто. XML больше, массивнее и приятнее на вид. К тому же его чуть легче сопровождать; правда, в итоге вы получаете копну ответов даже на простой запрос. Но все равно, его-то мы здесь и используем.
Если честно, большой разницы между ними нет, но XML – практически универсальный язык для web, и если вы научитесь работать с вызовами API через XML, это сослужит вам хорошую службу.
Python хорошо справляется с XML и имеет готовые модули для работы с ним... но мы забегаем вперед. Первым делом определим, как мы будем взаимодействовать с API Digg. И, подобно многим запасливым социальным web-сайтам, Digg располагает массой документации для программистов о том как использовать API. Ура!
Большая кнопка «Digg it»
Зайдем на сайт Digg API (http://apidoc.digg.com) и посмотрим, что там предлагается. Доступ к API осуществляется посредством запросов к главному web-сайту. Возможно, вы уже знакомы с этим – имеется набор значений, передаваемых на web-сервер для обработки; начинаются они с ? и разделяются &. Чтобы это опробовать, не нужно даже писать ни строчки кода самостоятельно: достаточно набрать URL и ввести его в браузере. Поскольку мы собираемся использовать стандартный XML-отклик, то браузер типа Firefox отобразит полученный XML-код прямо в своем окне, не требуя предварительно сохранить его в файл, что есть великое благо. В конце концов, нуднее, чем ввод сложного запроса и получение ошибки в ответ, может быть только необходимость загрузки файла в текстовый редактор ради выяснения, что он не работает.
Для активации конкретных функций API Digg использует специальные конечные точки (endpoints), или URL-пути. Например, если необходимо найти список последний горячих новостей [hot list], перейдите по адресу http://services.digg.com/stories/hot.
Опробуйте это в вашем браузере – и, однако, получите сообщение об ошибке. Единственной оговоркой Digg при предоставлении данного сервиса является то, что приложение, делающее запрос, должно иметь свой ключ (или API-ключ). Это распространено среди web-служб – они хотят иметь способ определить конкретного клиента, и вовсе не из подлости: если что-то пойдет не так и некто будет опрашивать сервер каждые 10 миллисекунд, должна быть возможность блокировать его, не останавливая API-сервис как целое.
- Метамодернизм в позднем творчестве В.Г. Сорокина
- ЛитРПГ - последняя отрыжка постмодерна
- "Ричард III и семиотика"
- 3D-визуализация обложки Ridero создаем обложку книги при работе над самиздатом.
- Архитектура метамодерна - говоря о современном искусстве, невозможно не поговорить об архитектуре. В данной статье будет отмечено несколько интересных принципов, характерных для построек "новой волны", столь притягательных и скандальных.
- Литература
- Метамодерн
- Рокер-Прометей против изначального зла в «Песне про советскую милицию» Вени Дркина, Автор: Нина Ищенко, к.ф.н, член Союза Писателей ЛНР - перепубликация из журнала "Топос".
- Как избавиться от комаров? Лучшие типы ловушек.
- Что делать если роблокс вылетает на windows
- Что делать, если ребенок смотрит порно?
- Почему собака прыгает на людей при встрече?
- Какое масло лить в Задний дифференциал (мост) Visco diff 38434AA050
- О чем может рассказать хвост вашей кошки?
- Верветки
- Отчетность бюджетных учреждений при закупках по Закону № 223-ФЗ
- Срок исковой давности как правильно рассчитать
- Дмитрий Патрушев минсельхоз будет ли преемником Путина
- Кто такой Владислав Поздняков? Что такое "Мужское Государство" и почему его признали экстремистским в России?
- Как правильно выбрать машинное масло в Димитровграде?
- Как стать богатым и знаменитым в России?
- Почему фильм "Пипец" (Kick-Ass) стал популярен по всему миру?
- Как стать мудрецом?
- Как правильно установить FreeBSD
- Как стать таким как Путин?
- Где лучше жить - в Димитровграде или в Ульяновске?
- Почему город Димитровград так называется?
- Что такое метамодерн?
- ВАЖНО! Временное ограничение движения автотранспортных средств в Димитровграде
- Тарифы на электроэнергию для майнеров предложено повысить
В этом отношении Digg немного необычен – он не требует полной регистрации ключа API: просто введите URL вашего web-проекта или сайта с исходным текстом клиентского приложения. И если мы вновь обратимся к Digg, уже с ключом http://services.digg.com/stories/hot/?appkey=http://www.linuxformat.ru, экран заполнится структурированным текстом. Символ ? в URL означает запрос, а нам надо передать несколько значений. Стандартный формат для этого – список пар «ключ–значение», разделенных амперсандом, &. Если мы теперь поменяем наш URL на http://services.digg.com/stories/hot/?appkey=http://www.linuxformat.ru&count=1, то увидим только первую статью. Естественно, можно указать другое число или любые другие переменные, принимаемые этим запросом. Как узнать, что это за переменные? Ну, придется попросить Digg опубликовать их. В данном случае вы найдете аргументы для конечных точек внизу страницы http://apidoc.digg.com/ListStories.
Digg и Python
Итак, мы ознакомились с основами Digg API. Можно вводить URL и получатьв замен XML-код. Здорово; но как бы провернуть это программно? Что же, для начала необходим способ открытия URL. Стандартный модуль Python, urllib, может сделать это для нас, поэтому запустим оболочку Python (откройте окно терминала и просто введите python) и посмотрим, что можно сделать.
>>> url=’http://services.digg.com/stories/hot/?’ >>> appkey=’http://www.linuxformat.ru’ >>> import urllib >>> diggargs ={ ‘count’: 1, ‘appkey’: appkey} >>> foo=urllib.urlencode(diggargs) >>> request = url+foo >>> request ‘http://services.digg.com/stories/hot/?count=1&appkey=http%3A%2F%2Fwww.linuxformat.ru’ >>>
Тут требуется небольшое пояснение. Сперва мы сохраняем базовый URL и ключ приложения в виде строк, потому что далее они будут часто использоваться. После импорта модуля urllib нам надо определить некоторые переменные для передачи Digg. Здесь мы воспользовались словарем Python. Это простая конструкция, заключенная в фигурные скобки – она хранит пары «ключ–значение» и ведет себя схоже со списками. Сперва указывается ключ, затем следует двоеточие, а далее значение. Тип значения может быть любым из распознаваемых Python, но чаще всего это строки или целые числа.
Зачем нужен словарь?
Но зачем, собственно, создавать из аргументов словарь? Во-первых, ради стройности кода, а во-вторых, в библиотеке urllib имеются полезные функции, которые преобразуют его в строку-запрос вместо нас. Это не так просто, как конкатенация (объединение) всех строк, потому что в HTTP есть соглашения о символах, допустимых в запросах. Поэтому в следующей строке вызывается функция urllib.urlencode для преобразования нашего словаря в строку-запрос. Еще одно преимущество использования словарей – простота добавления или изменения значений, а строку-запрос можно сгенерировать заново. А если бы мы напрямую конвертировали аргументы в строку-запрос, внесение изменений было бы более хитрым (или муторным) делом.
Массивный отклик
Запрос [request] строится простым объединением базового URL и строки-запроса. Любопытства ради, можете просто ввести имя этой переменной, и Python напечатает ее значение: в данном случае – с трудом читаемый URL, результат использования верной кодировки. Итак, что же мы получим, подключившись к серверу с этим запросом? Ответ должен выглядеть примерно так:
>>> response = urllib.urlopen(request) >>> response.read() ‘<?xml version=”1.0” encoding=”utf-8” ?>\n<stories timestamp=”1251657872” total=”13711” offset=”0” count=”1”>\n <story link=”http://myfirstfail.com/2009/08/24/funny-baby-photos-im-really-excited-to-be-here/” submit_ date=”1251584276” diggs=”125” id=”15364594” comments=”18” href=”http://digg.com/people/I_m_REALLY_Excited_to_be_ Here” status=”upcoming” media=”images”>\n <description></description>\n <title>I\'m REALLY Excited to be Here!</title>\n <user name=”sungoddess808” registered=”1201436227” profileviews=”40965” fullname=”Sunshine ” icon=”http://digg. com/users/sungoddess808/l.png” />\n <topic name=”People” short_name=”people” />\n <container name=”Offbeat” short_name=”offbeat” />\n <thumbnail originalwidth=”500” originalheight=”426” contentType=”image/jpeg” src=”http://digg.com/people/I_m_REALLY_Excited_to_be_Here/t.jpg” width=”80” height=”80” />\n <shorturl short_url=”http://digg.com/d312T22” view_count=”582” />\n </story>\n</stories>‘
Функция urlopen возвращает файлоподобный объект, с которым можно обращаться как с любым другим файл-объектом. Это полезно, если вы ожидаете в ответ огромный объем данных, но я сомневаюсь, что из-за экспериментов нашего урока Digg заполнит всю вашу память. Далее, response.read() просто выводит «файл», и можно совместить эти две команды:
>>> response = urllib.urlopen(request).read()
Такой трюк применим к большинству объектов Python, хотя затрудняет понимание кода.
Наша уловка сработала, и мы получили ответ – кучу XML-кода для обработки. Чтобы получить из нее XML-объект, необходимо задействовать кое-какие методы из XML-модуля Python, а именно
>>> from xml.dom import xml.minidom >>> x = minidom.parseString(response)
Выуживание данных из объектов и построение из этой информации правильно структурированного XML-файла известно в мире XML как маршалинг [marshalling, упорядочивание]. Но нам-то нужна обратная операция – создать объект Python из данных. Нижеследующий кусок кода, вероятно, один из наиболее часто копируемых, по крайней мере для Python и XML. По-моему, он восходит к коду, написанному Марком Пилгримом [Mark Pilgrim] (автор книги В глубь языка Python, http://ru.diveintopython.org), а кто несогласен – пишите на известный адрес...
class Bag: pass def unmarshal(element): rc = Bag() if isinstance(element, minidom.Element): for key in element.attributes.keys(): setattr(rc, key, element.attributes[key].value) childElements = [e for e in element.childNodes \ if isinstance(e, minidom.Element)] if childElements: for child in childElements: key = child.tagName if hasattr(rc, key): if type(getattr(rc, key)) <> type([]): setattr(rc, key, [getattr(rc, key)]) setattr(rc, key, getattr(rc, key) + [unmarshal(child)]) elif isinstance(child, minidom.Element) and \ (child.tagName == ‘Details’): # Делаем первый элемент Details ключом setattr(rc,key,[unmarshal(child)]) else: setattr(rc, key, unmarshal(child)) else: text = “”.join([e.data for e in element.childNodes \ if isinstance(e, minidom.Text)]) setattr(rc, ‘text’, text) return rc
Опять немного поясним. Первая странность – класс Bag, который вроде и описан, но пуст. В Python такое допустимо – и правда, как узнать, что будет в классе, пока не распакованы данные? Это прекрасно демонстрирует гибкость Python; он допускает классы объектов, которые можно создавать в процессе выполнения.
- Метамодернизм в позднем творчестве В.Г. Сорокина
- ЛитРПГ - последняя отрыжка постмодерна
- "Ричард III и семиотика"
- 3D-визуализация обложки Ridero создаем обложку книги при работе над самиздатом.
- Архитектура метамодерна - говоря о современном искусстве, невозможно не поговорить об архитектуре. В данной статье будет отмечено несколько интересных принципов, характерных для построек "новой волны", столь притягательных и скандальных.
- Литература
- Метамодерн
- Рокер-Прометей против изначального зла в «Песне про советскую милицию» Вени Дркина, Автор: Нина Ищенко, к.ф.н, член Союза Писателей ЛНР - перепубликация из журнала "Топос".
- Как избавиться от комаров? Лучшие типы ловушек.
- Что делать если роблокс вылетает на windows
- Что делать, если ребенок смотрит порно?
- Почему собака прыгает на людей при встрече?
- Какое масло лить в Задний дифференциал (мост) Visco diff 38434AA050
- О чем может рассказать хвост вашей кошки?
- Верветки
- Отчетность бюджетных учреждений при закупках по Закону № 223-ФЗ
- Срок исковой давности как правильно рассчитать
- Дмитрий Патрушев минсельхоз будет ли преемником Путина
- Кто такой Владислав Поздняков? Что такое "Мужское Государство" и почему его признали экстремистским в России?
- Как правильно выбрать машинное масло в Димитровграде?
- Как стать богатым и знаменитым в России?
- Почему фильм "Пипец" (Kick-Ass) стал популярен по всему миру?
- Как стать мудрецом?
- Как правильно установить FreeBSD
- Как стать таким как Путин?
- Где лучше жить - в Димитровграде или в Ульяновске?
- Почему город Димитровград так называется?
- Что такое метамодерн?
- ВАЖНО! Временное ограничение движения автотранспортных средств в Димитровграде
- Тарифы на электроэнергию для майнеров предложено повысить
Анархия кода?
Функция unmarshal – просто рекурсивная процедура, которая пошагово проходит каждый узел дерева XML DOM и собирает из него объект Python. Желая создать модуль API для Python, выполняющий интерпретацию вывода Digg, вы можете делать это более структурировано и осмысленно, потому что структура XML известна заранее. А приведенный метод – из разряда всеобъемлющих, с тем недостатком, что получающийся объект все еще неуклюж. Однако небольшая пост-обработка расставит все по местам.
Мы получили список контейнеров story, заключенных в контейнер с именем stories. Каждый из них имеет свои собственные подузлы для комментариев, ID, URL и так далее. Если мы хотим взглянуть на объекты story, следует просто в цикле пройтись по контейнеру stories, вот так:
>>> for item in bar.stories.story: >>> print item.id, item.link, item.title.text
Ничто не мешает добавлять данные в эту структуру программно. Что если, например, полюбопытствовать, где опубликованы все эти истории? На это имеется полезная свободная библиотека с именем GeoIP, выставляющая соответствие между IP-адресами и странами.
Добавляем данные
Модуль GeoIP имеется в основных дистрибутивах, или можно загрузить его с MaxMind (http://www.maxmind.com/app/python). Все очень просто: вы создаете объект GeoIP, затем используете его методы для определения кода или названия страны по имени домена web-сервера. Вот простой пример:
>>> import GeoIP >>> geo=GeoIP.new(GeoIP.GEOIP_STANDARD) >>> geo.country_name_by_name(‘google.com’) ‘United States’
Проще некуда. К сожалению, ему необходим только домен, а не весь URL. Но мы можем импортировать еще один стандартный модуль Python, под названием urlparse (http://www.python.org/doc/2.5.2/lib/moduleurlparse.html), который разбивает URL на части.
>>> import urlparse >>> for item in bar.stories.story: >>> item.country=geo.country_name_by_name(urlparse.urlparse(item.link).netloc) >>> print item.country
Мы переписали наш цикл и создали внутри него новое свойство объекта item с именем country. Передача вырезанного имени домена от функции urlparse к функции GeoIP выдает название страны в виде строки.
Можно зайти дальше и на основании значений country проследить частоту появления различных стран, скажем, в первой сотне самых посещаемых сайтов. Это весьма легко сделать: объявим пустой словарь, затем будем добавлять единицу к величине ключа данной страны по ходу цикла обработки. Если ключа не существует, то используем значение по умолчанию – ноль. Словарь потом можно преобразовать в упорядоченный список и построить гистограмму частоты появления стран.
- Метамодернизм в позднем творчестве В.Г. Сорокина
- ЛитРПГ - последняя отрыжка постмодерна
- "Ричард III и семиотика"
- 3D-визуализация обложки Ridero создаем обложку книги при работе над самиздатом.
- Архитектура метамодерна - говоря о современном искусстве, невозможно не поговорить об архитектуре. В данной статье будет отмечено несколько интересных принципов, характерных для построек "новой волны", столь притягательных и скандальных.
- Литература
- Метамодерн
- Рокер-Прометей против изначального зла в «Песне про советскую милицию» Вени Дркина, Автор: Нина Ищенко, к.ф.н, член Союза Писателей ЛНР - перепубликация из журнала "Топос".
- Как избавиться от комаров? Лучшие типы ловушек.
- Что делать если роблокс вылетает на windows
- Что делать, если ребенок смотрит порно?
- Почему собака прыгает на людей при встрече?
- Какое масло лить в Задний дифференциал (мост) Visco diff 38434AA050
- О чем может рассказать хвост вашей кошки?
- Верветки
- Отчетность бюджетных учреждений при закупках по Закону № 223-ФЗ
- Срок исковой давности как правильно рассчитать
- Дмитрий Патрушев минсельхоз будет ли преемником Путина
- Кто такой Владислав Поздняков? Что такое "Мужское Государство" и почему его признали экстремистским в России?
- Как правильно выбрать машинное масло в Димитровграде?
- Как стать богатым и знаменитым в России?
- Почему фильм "Пипец" (Kick-Ass) стал популярен по всему миру?
- Как стать мудрецом?
- Как правильно установить FreeBSD
- Как стать таким как Путин?
- Где лучше жить - в Димитровграде или в Ульяновске?
- Почему город Димитровград так называется?
- Что такое метамодерн?
- ВАЖНО! Временное ограничение движения автотранспортных средств в Димитровграде
- Тарифы на электроэнергию для майнеров предложено повысить
#!/usr/bin/python import urllib from xml.dom import minidom import urlparse, GeoIP, operator url=’http://services.digg.com/stories/hot/?’ appkey=’http://linuxformat.co.uk’ geo=GeoIP.new(GeoIP.GEOIP_MEMORY_CACHE) class Bag: pass def unmarshal(element): rc = Bag() if isinstance(element, minidom.Element): for key in element.attributes.keys(): setattr(rc, key, element.attributes[key].value) childElements = [e for e in element.childNodes \ if isinstance(e, minidom.Element)] if childElements: for child in childElements: key = child.tagName if hasattr(rc, key): if type(getattr(rc, key)) <> type([]): setattr(rc, key, [getattr(rc, key)]) setattr(rc, key, getattr(rc, key) + [unmarshal(child)]) elif isinstance(child, minidom.Element) and \ (child.tagName == ‘Details’): # делаем первый элемент Details ключом setattr(rc,key,[unmarshal(child)]) else: setattr(rc, key, unmarshal(child)) else: text = “”.join([e.data for e in element.childNodes \ if isinstance(e, minidom.Text)]) setattr(rc, ‘text’, text) return rc diggargs ={ ‘count’: 100, ‘appkey’: appkey} foo=urllib.urlencode(diggargs) request = url+foo response = urllib.urlopen(request).read() x = minidom.parseString(response) bar = unmarshal(x) hist = {} for item in bar.stories.story: item.country=geo.country_name_by_name(urlparse.urlparse(item.link).netloc) hist[item.country]=hist.get(item.country, 0) +1 sorted = sorted(hist.items(), key=operator.itemgetter(1),reverse=True) print sorted
Сегодня мы освоили солидный кусок, хотя занимались всего одной точкой входа для Digg. Для более полезного API вы, возможно, захотите создать класс и несколько объектов, чтобы описать пользователей, заметки и тому подобное, и примените описанные здесь советы, чтобы заполнить их. Digg – это, в основном, трафик в одну сторону, но в следующий раз мы рассмотрим также и запись данных, создав графический клиент Flickr.