Pull to refresh

Пишем свой рейтинг популярных записей русскоязычных блогов на базе Яндекс.API, часть 1

Reading time 7 min
Views 1.9K
Жил-был в составе поиска по блогам Яндекса рейтинг популярных записей, который для многих был такой себе ежедневной газеткой. Но решили в Яндексе его закрыть да предоставили API, чтобы каждый желающий мог сделать свой рейтинг популярных записей по блогам, чем мы собственно сегодня и займемся. Писать будем на PHP.


Итак, для начала ознакомимся с API статистики записей Поиска по блогам.

Тут все просто, мы имеем RSS ленту статистики записей по блогам за последние 24 часа, разбитую на страницы по 50 записей.

На первой странице выводятся самые свежие записи. Номер страницы, которую нам нужно получить задается параметром p=<номер страницы> в URL адресе, по которому мы обращаемся к API, например: http://blogs.yandex.ru/entriesapi?p=1.

Перейдите по ссылке выше и посмотрите на исходный код этой страницы (Вид->просмотреть источник или Ctrl+U, если у вас FireFox/Opera/Chrome). Мы видим обычный XML документ, который будем читать и анализировать с помощью PHP. Нас интересуют информация о записях, находящаяся внутри тегов <item>. Названия вложенных элементов говорят сами за себя, это:
  • author – ссылка на блог/страницу автора;
  • description короткое описание (обычно пусто);
  • link ссылка на пост;
  • pubDate дата и время публикации;
  • title – заголовок поста;
  • yablogs:commenters – количество разных русскоязычных комментаторов у записи за все время ее существования;
  • yablogs:commenters24 – количество разных русскоязычных комментаторов у записи;
  • yablogs:comments – общее количество комментариев к записи за все время ее существования;
  • yablogs:comments24 – количество комментариев к записи за последние 24 часа;
  • yablogs:links – общее количество ссылок на запись за все время ее существования;
  • yablogs:links24 – количество ссылок на запись за последние 24 часа;
  • yablogs:links24weight – взвешенное количество ссылок на запись за последние 24 часа(с отфильтрованными накрутками и спамными ссылками);
  • yablogs:linksweight – общее взвешенное количество ссылок на запись (с отфильтрованными накрутками и спамными ссылками);
  • yablogs:visits24 – примерное количество посетителей записи за последние 24 часа;
  • yablogs:ppb_username – имя (nickname) автора поста.

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

Для начала нужно определиться с инструментом для работы с XML. В PHP manual есть просто таки огромный раздел XML manipulation, где вы можете найти массу различных средств для работы с XML документами. Одним из самых простых, удобных и в то же время мощных решений является расширение SimpleXML, которое поставляется с PHP начиная с 5-й версии и включено по умолчанию. С ним мы и будем работать. Поверьте мне, это действительно очень хороший инструмент, позволяющий просто и удобно работать с XML документами. Продемонстрирую это:
$xml = simplexml_load_file('http://blogs.yandex.ru/entriesapi');
echo '<b>Это заголовок канала:</b> ',
$xml->channel->title, '<br>',
'<b>А это заголовок последнего поста:</b> ',
$xml->channel->item[0]->title, '<br>',
'<b>Время публикации последнего поста: </b> ',
$xml->channel->item[0]->pubDate;

Думаю, тут все понятно: в первой строке мы загружаем первую страницу ленты популярных записей в переменную $xml (функция simplexml_load_file возвращает экземпляр класса SimpleXMLElement), которую далее можем интерпретировать как объект, соответствующий нашему XML документу, что мы собственно и делаем.

Если мы обращаемся к произвольному полю такого объекта, выполняется поиск дочернего элемента XML дерева с именем, соответствующим имени запрошенного поля и если такой элемент найден, возвращается объект, являющийся также экземпляром класса SimpleXMLElement, или массив таких объектов.

Благодаря такой логике работы мы можем выполнять цепочки запросов вида: $xml->someElement->children->childrenOfChildren.

Обратите внимание, что элементов item в нашем XML документе много, поэтому $xml->channel->item возвращает не один объект, а массив объектов, предоставляющих доступ к этим элементам. В примере мы обратились к самому первому в документе элементу item по индексу [0], и вывели его заголовок и дату публикации на экран (в браузер).

Альтернативный способ получить нужную ветвь XML документа в SimpleXML — это использование XPath, языка запросов к элементам XML дерева. В классе SimpleXMLElement для этого имеется метод xpath(string $path), возвращающий массив экземпляров класса SimpleXMLElement или FALSE в случае ошибки.

Пример использования XPath:

$items=$xml->xpath('channel/item');

Чтобы получить аналогичный набор элементов без XPath, нужно выполнить:

$items=$xml->channel->item;

Использование XPath или цепочек вызовов полей — это дело вкуса, в нашем случае мы будем использовать XPath, чтобы обратиться к элементам типа yablogs:links, где есть символ ":", так как он мешает интерпретировать эти элементы как поля объекта в PHP.

Ну давайте уже что-нибудь сделаем. Например функцию, получающую информацию о всех записях за 24 часа. Собственно, вот:
  1. define ('MAX_PAGES',200);
  2. function load_all() {
  3. $all_items=array();
  4. for ($i=1; true;$i++) {
  5. $xml = simplexml_load_file('http://blogs.yandex.ru/entriesapi?p=' . $i);
  6. $items=$xml->xpath('channel/item');
  7. if (empty($items)) {
  8. break;
  9. }
  10. $all_items=array_merge($all_items,$items);
  11. if ($i>=MAX_PAGES) break;
  12. }
  13. return $all_items;
  14. }


Такая функция конечно же будет работать очень медленно и скорее всего упрется в ограничение на время выполнения php скриптов: по умолчанию — 30 секунд, поэтому полученные данные нужно обязательно кэшировать, а само их получение выполнять не при открытии страницы, а через планировщик задач crontab. Мы будем сохранять полученную информацию в базу данных, использовать будем MySQL, но об этом в следующей части, а пока вернемся к работе с XML.

Давайте уже в этом уроке соберем наш рейтинг популярных записей русскоязычных блогов с минимальным функционалом и отложим на потом кэширование, расширение функционала, придание ООП'шности и MVC'шности нашему коду.

Чтобы долго и нудно не ждать результата выполнения функции load_all(), давайте зададим ей ограничение: будем обрабатывать только первые 4 страницы RSS ленты, выдаваемой Яндексом. Специально для этого я ввел константу MAX_PAGES, заменяем значение 200 в первой строчке на 4.

Наш рейтинг должен уметь сортировать записи по количеству комментариев, количеству ссылок и количеству посещений. Мы уже имеем функцию, с помощью которой можем получить список записей. Значит задача состоит в сортировке этого списка.

Если бы мы заносили информацию о всех записях в базу данных скриптом, вызываемым через планировщик задач, а при выдаче информации пользователю, брали бы ее из БД, то мы бы воспользовались возможностями SQL для сортировки, но это мы будем делать во второй части урока, а сейчас сделаем по-быстрому сортировку средствами PHP.

Поможет нам в этом стандартная функция PHP usort, позволяющая сортировать массивы с использованием своей функции для сравнения элементов массива.

Элементами массива у нас являются экземпляры класса SimpleXMLElement, инициализированные элементами XML дерева <item>.

Рассмотрим, как мы можем получить к примеру количество комментариев записи:
  1. $xml = simplexml_load_file('http://blogs.yandex.ru/entriesapi');
  2. $item=$xml->channel->item[12];//Получаем какой-нибуть XML элемент item, например 13-й.
  3. $comments_arr=$item->xpath('yablogs:comments');//получаем массив объектов
  4. $comments_obj=$comments_arr[ 0];//объект у нас должен быть один, это мы знаем
  5. $comments=(int)$comments_obj;//приводим его тип к целочисленному (int), чтобы можно было выполнить сравнение


А теперь можно написать и функцию сравнения, причем универсальную.
  1. $cmp='yablogs:comments';//по этому параметру сравниваем,
  2. //к функции сравнения при использовании в usort есть требование:
  3. //она должна принимать два только параметра,
  4. //соответствующие сравниваемым элементам массива,
  5. //поэтому делаем $cmp просто глобальной переменной
  6. function cmp($a, $b)
  7. {
  8. global $cmp;
  9. $a=$a->xpath($cmp);
  10. $b=$b->xpath($cmp);
  11. $a=(int)$a[0];
  12. $b=(int)$b[0];
  13. if ($a == $b) {
  14. return 0;
  15. }
  16. return ($a > $b) ? -1 : 1;
  17. }


У нас будет функция sort_by, в которую будем передавать ссылку на массив и строку, соответствующую XML элементу, по которому будем сортировать (критерий сравнения). sort_by в свою очередь будеть вызывать стандартную функцию usort, передавая ей ссылку на массив и присваивать глобальной переменной $cmp критерий сравнения.
  1. function sort_by($sort_by,$i)
  2. {
  3. global $cmp;
  4. $cmp=$sort_by;
  5. usort($i,'cmp');
  6. }


Почти готово, теперь мы можем к примеру вывести отсортированные по количеству комментариев записи вот так:
  1. $items=load_all();
  2. sort_by('yablogs:comments',&$items);
  3. foreach ($items as $item) {
  4. $comments=$item->xpath('yablogs:comments');
  5. $links=$item->xpath('yablogs:links');
  6. $visits=$item->xpath('yablogs:visits24');
  7. echo "<a href='$item->link'>$item->title</a><br>",
  8. "Комментариев: $comments[0]<br>",
  9. "Ссылок: $links[0]<br>",
  10. "Просмотров: $visits[0]<hr>";
  11. }


Как именно сортировать наш список, будем передавать параметром URI sort_by, который будет доступен в php как $_GET['sort_by']. Создадим три ссылки для разных типов сортировки, для этого перед тегом <?php, обозначающим начало php кода, пишем:
  1. <div style="text-align:center;">
  2. <a href="index.php/?sort_by=comments">Самые комментируемые</a>
  3. <a href="index.php/?sort_by=visits24">Самые посещаемые</a>
  4. <a href="index.php/?sort_by=links">Самые цитируемые</a>
  5. </div>


Нам осталось только получить в PHP критерий сортировки и отсортировать все соответствующим образом. Для этого строку с sort_by('yablogs:comments',&$items) заменяем на это:
  1. if (isset($_GET['sort_by'])){
  2. $crit=$_GET['sort_by'];
  3. }else{
  4. $crit='comments';
  5. }
  6. sort_by('yablogs:' . $crit ,&$items);


И напоследок добавим немного оформления с помощью CSS, чтобы наш рейтинг смотрелся получше:
  1. <style>
  2. div{padding:20px; background-color:#EEE;}
  3. hr{border:none; border-bottom:1px dashed yellow;}
  4. </style>


Исходник того, что мы сделали вы можете скачать здесь: http://www.nayjest.ru/userfiles/yabdex.blograting.by.nayjest.zip

Как видите, все очень просто.

В следующих уроках я расскажу, как сделать из этого полноценный веб-сервис, где все будет ООП'шненько, будет работа с БД, архитектура MVC, валидный HTML, кэширование, может даже AJAX и вообще все, что захотите (предлагайте в комментариях!).

Надеюсь, было интересно и полезно. Чтобы не пропустить следующие уроки, follow me on Twitter. Спасибо за внимание, жду ваших комментариев!
Tags:
Hubs:
+1
Comments 13
Comments Comments 13

Articles