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

    Жил-был в составе поиска по блогам Яндекса рейтинг популярных записей, который для многих был такой себе ежедневной газеткой. Но решили в Яндексе его закрыть да предоставили 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. Спасибо за внимание, жду ваших комментариев!
    Share post

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 13

      +1
      Ну уже как то совсем для новичков…
      Много воды :)

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

        По поводу «много воды» — можете посоветовать мне, что выбросить из статьи, я старался ничего не упустить, чтобы не было непонятных моментов даже для начинающих, видимо перестарался :)
        –1
        Те, кто минусует этот топик и мою карму, расскажите пожалуйста, в чем ошибки / недоработки этой статьи, очень нужен фидбек, короче, направьте меня на путь истиный, а то вроде бы и старался… Хочу писать хорошие статьи, правда :)
          –2
          Наверное минисуют потому что этот топ блогов приелся, сначала куча сайтов была, реализующих этот функционал, теперь статьи пошли.
          По статье:
          Я бы посоветовал использовать подсветку синтаксиса.
          И еще на счет таймаута в 30сек: это время вроде как не учивает сетевые коннекты.
            +1
            много — не мало. Через полгода — год останутся только самые популярные и самые стойкие
            –2
            ну тут не школьный форум и html/php тут знают на 5/5 как минимум 2/3 хабраюзеров. А новички для которых это написано хабр читают по диагонали. Зря старались наверно)
              0
              дописывайте цикл, полагаю, в следующих статьях будет меньше очевидных вещей.
                0
                Да не парься) тут полно идиотов. Меня тож в минус загнали за подобные мануалы для новичков. Спасибо за статью — годная! Я в свое время писал рейтинг для блогов с нуля со своим краулером даже))
                0
                Спасибо
                то, что надо))
                видимо, я как раз представитель того жалкого меньшинства, который не знает php на 5/5 или 100/100 и пр. так что очень в тему
                жду продолжения
                  0
                  Написать — это 10% успеха
                  изобрести что-то новое и внедрить — еще 20%
                  и 70% — самое сложное — продвинуть :)
                  кстати проект topblogi.ru обошел всех кто тут пиарился, хотя его так жутко заминусовали
                  еще я бы на месте автора добавил картинок — чтобы было более наглядно
                    +1
                    Ну, мне собственно нечего продвигать, если вы имеете в виду рейтинги блогов, как бы мопед не мой, я просто разместил объяву… как сделать такой рейтинг :)
                    По поводу успеха — абсолютно согласен, но думаю, следует добавить, что еще настоящий успех приходит к таким проектам, которые сами себя продвигают, привлекая эти 70% успеха, а привлекают в первую очередь своим качеством и актуальностью, уменьшая затраты на продвижение.

                    Спасибо за комментарий.
                    0
                    А где вторая часть (с «оопэшненько»)? Просто я вот прям щас уселся набросать такой топ — реально ломает лишний код писать))) коли где-то уже готовые классы есть )
                      0
                      … написал. для того лишь, чтобы понять, что http://blogs.yandex.ru/entriesapi теперь вообще ни на что не годится :) там такая жесть…

                    Only users with full accounts can post comments. Log in, please.