PHP класс для работы с Яндекс.XML



    Уже продолжительное время доступен сервис Яндекс.XML — сие есть не что иное, как поисковый сервис, который позволяет делать автоматические поисковые запросы к Яндексу и публиковать его ответы у себя на сайте и данный пост посвящен приручению сего зверя с использованием PHP.

    !: Данный пост есть развитие диалога в топике habrahabr.ru/blogs/php/36932

    Для начала нам необходимо зарегистрировать IP адрес сайта в базе Яндекса. После этого нам станет доступен бесплатный вариант поиска, который предполагает не более 1000 запросов в сутки с одного IP. Так же одним из условий использования сервиса является размещение фразы «Поиск реализован на основе Яндекс.XML» на странице результатов поиска.

    Теперь приступим непосредственно к PHP, нам понадобится класс Yandex (скромное название — могут не понять), его Вы можете скачать со странички проекта на Code-Google, так же есть доступ к SVN репозиторию:

    svn checkout yandex.googlecode.com/svn/trunk yandex-read-only


    Требования вполне приемлемые:
    • PHP 5.1+
    • SimpleXML
    • CURL

    Приступим, для начала подключаем сам класс:

    require_once 'Yandex.php';


    Далее — нам необходимо забрать из реквеста поисковый запрос, номер страницы и сайт по которому будем искать (вполне вероятно Вам понадобится гораздо больше параметров, но будем считать это необходимым минимумом):

    // забираем "query", "page" и "host" с request'а
    $query = isset($_REQUEST['query'])?$_REQUEST['query']:'';
    $page = isset($_REQUEST['page']) ?$_REQUEST['page']:0;
    $host = isset($_REQUEST['host']) ?$_REQUEST['host']:null;


    Теперь непосредственно манипуляции с классом Yandex:

    if ($query) {
        // создаем экземпляр класса Yandex
        $Yandex = new Yandex();
        
        $Yandex -> query($query)               // устанавливаем поисковый запрос 
                -> host($host)                      // ограничиваемся поиском по сайту
                -> page($page)                     // текущая страница
                -> limit(10)                           // результатов на странице
                -> set('max-title-length',   160)   // тонкая настройка поисковой выдачи (см. http://code.google.com/p/yandex/source/browse/trunk/Yandex.php#48)
                -> set('max-passage-length', 200)
                -> request()                        // отправляем запрос
                ;
    }
    


    Если всё прошло гладко, то результат будет доступен в "$Yandex->result" — сие есть SimpleXML объект, ничем и никак не порезанный — дабы предоставить полную свободу действий для его обработки. Далее привожу пример вывода результатов поиска (HTML опущен):

    // проверяем всё ли гладко
    if (isset($Yandex) && empty($Yandex->error)) : 
    
        // вот таким образом мы стучимся к результатам
        foreach ($Yandex->result->response->results->grouping->group as $group) :
            // вывод URL
            echo $group->doc->url;
            // вывод заголовка - метод Yandex::highlight выделяет поисковую фразу
            Yandex::highlight($group->doc->title);
            // выводим пассажи
            foreach ($group->doc->passages->passage as $passage) :
                 Yandex::highlight($passage);                 
            endforeach;
        endforeach;
    
        // далее выводим постраничную навигацию, она немного громоздка
        foreach ($Yandex->pageBar() as $page => $value) :
                    // switch statement for $value['type']
                    switch ($value['type']) {
                          // ссылка на страничку
                    	case 'link':
                    		echo '<a href="'. $url .'&page='. $page .'" title="Page '. ($page+1) .'">'. sprintf($value['text'], $page+1) .'</a> | ';
                    		break;
                          // текущая страница
                    	case 'current':
                    		echo sprintf($value['text'], $page+1) .' | ';
                    		break;
                          // текст разделителя - ".."
                    	case 'text':
                    		echo $value['text'] .' | ';
                    		break;
                    
                    	default:
                    		break;
                    }
        endforeach;
    
    // если что-то не так - выводим ошибку
    elseif(isset($Yandex) && isset($Yandex->error)):
        echo $Yandex->error;
    endif;
    


    В данном примере используются конструкции ввида «if (..):… endif;», т.к. они наиболее подходят для шаблонизаторов с нативным PHP синтаксисом, для оборачивания сего в Smarty Вам понадобиться заасайнить $Yandex в шаблон и далее переделываем пример:

    // будет что-то типа:
    $Smarty->assign("Yandex", $Yandex);


    Разбирать сам класс по запчастям, я думаю, особо не стоит — кто знает PHP и так поймет — благо комментарии присутствуют, да и ничего военного в нем нет — все достаточно просто. Если же есть пожелания иль замечания — пишите — будем обсуждать…

    Попробывать скрипт на вкус можно на страничке http://yandex.hohli.com/
    Поделиться публикацией
    Комментарии 33
      0
      Спасибо как раз то, что нужно.
        +4
        YaXML — какой-то не такой, там 1000 запросов мона с определенного АйПи в сутки… Да и слухи ходили и рядах seo-спецов, что выдача YaXML отличается бывает от выдачи, что обычным пользователям показывается.

        ИМХО намного лучше юзать обычную пользовательскую выдачу, как я делаю, ничего сложного нету:
        — запрос GET, юзабельные параметры: text — текст запроса, p — номер страницы выдачи (0, 1, ...) да и numdoc — число рез-тов на страницу (10, 20, 50 вроде помню допустимы, ессессно, для уменьшения нагрузки используйте максимум)))
        — полученную страницу прогоняете через регулярное выражение, вот мой вариант, кстати, исправленный сегодня в учетом вчерашнего апа: #.*]*tabindex[^>]*href=«([^»]+)«[^>]*>(.+).*#Ui

        На выходе получаете массив (numdoc элементов в нем) массивов (3 эл-та в подмассиве: html с одним результатом выдачи, url найденной страницы выдачи, ее заголовок)

        ну и опять же, с учетом вчерашнего апа, теперь кликнув на результат выдачи, вы пойдете на что-то вроде clck.yandex.ru/redir/dtype=iweb/path=80.22.82/vars=84=86… reqid=1219118886-18378/*http://www.vinzavod.ru/
        Поэтому теперь еще надо дополнительно, чтобы извлечь url найденной страницы, нужно прогнать написанное выше через выражение: /[\*](http:.*)$/Ui, и получите на выходе: www.vinzavod.ru/

        Я класс на PHP написал, пользуюсь, не жалуюсь))
        Единственное что надо соблюдать, так это паузы между запросами, секунды 3 и более бывает вроде как достаточно, чтобы яндекс нас за робота не посчитал…

        P.S: Мог бы в блоги писать, оформил бы по этому статью
          0
          Блин, хабр похерил символы из регулярок, если что — пишите в личку, скину…
            0
            Код надо брать под тег:
            <code>твой код</code>
              0
              Обязательно учту, Спасибо!
                0
                Перепишите, пожалуйста, регулярные выражения или дайте ссылку для скачивания. Хочется попробовать.
                  0
                  Я сейчас как раз готовлю пост про то, что писал в коментах))
            0
            На скольких сайтах параллельно вы готовы гарантированно поддерживать этот код в боеспособном состоянии?

            Это к слову о преимуществах YaXML в случае, когда поиск нужен не на одном сайте и не на десяти…
              0
              Ээээм… Я писал с точки зрения решения задачи определения позиций определенного сайта в поисковиках по определенным словам и фразам ))
                0
                Согласен, в случае если YaML расходится с основной выдачей — ваше решение не только лучшее из двух, но и единственно верное.
              0
              За это вроде бы капчу показывают?
                0
                Да нет, если соблюдать временной промежуток, я ставлю рандомно — от 2 до 4 секунд, но опыт мне говорит, что надо поболее, все равно, каюсь, капча вываливается иногда…

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

                Как правило, анализируют сразу в нескольких поисковиках, потому можно все сделать таким образом, что не добить сначала яндекс, потом гугл и пр., а поочередно)) Тогда многократно падает вероятность показа капчи (что со стороны яндекса, что со стороны гугла), да и промежуток временный в 2-4 секунды уже будет не актуален вообще, либо для порядку, чтобы нагрузки не было, сократится максимум до 1 с… и не будет бесполезной утечкой времени))

                Подход, состоящий в парсинге пользовательской выдачи, конечно, посложнее, чем YaXML, но зато я точно знаю, что результаты аналогичны тому, что видят пользователи, и я не ограничен в количестве запросов))
                0
                пробовал и 3 секунды и больше, придумывал самые красивые заголовки, все равно банит как робота. Ну и 3 секунды тоже проблема, когда надо обработать сотни запросов.
                А xml да, отличается от обычной выдачи, что делает его бесполезным
                0
                Большое спасибо за статью!
                Буду пытаться подключить скрипт к своему сайту.
                Если будет что-то не получаться, можно будет задать вопрос?
                Спасибо.
                  +3
                  svn checkout yandex.googlecode.com/svn/trunk/

                  Хорошее имя у репозитория :)
                    –4
                    яндекс как всегда…

                    мало того, что все прёт у гугла… :)
                    –11
                    Боже, а что ж картинка — то в статье такого ужасного качества?!?!
                    не портьте первую страницу хабра!
                      0
                      на XSLT как-то это все приятнее выглядит
                        +2
                        Предлагаю автору взять мой вариант картинки, для солидности статьи.

                          0
                          Автор не будет против если я использую данную картинку и в своём блоге?
                            +1
                            Конечно не будет, автор специально рисовал для автора статьи ))
                            –2
                            Вы уверенны, что такая лесница на букве «Я» вместе с не реальным вензелем снизу добавит солидности?
                            Для солидности думаю будет достаточно написать
                            «PHP класс для работы с Яндекс.XML»
                              0
                              Мы тут не дизайн обсуждаем…
                              А моя картинка визуально показывает, о чем речь в статье.

                              От Вас же вижу второй критикующий комментарий в сторону картинки…
                              может вы блогом ошиблись?
                              0
                              Имхо букву «Я» лучше оставить оригинального цвета :)
                                0
                                Я хотел сделать под цветовую гамму хабра
                                да и красный цвет, очень агрессивно смотриться :)
                                  +2
                                  Зато фирменно :) По мне так этот голубой тоже ярковат, лучше взять цвет эмблемы Хабра:
                                  yandex_xml_habr.gif - Picamatic - upload your images
                                  или сделать комбинированный вариант:
                                  yandex_xml_combi.gif - Picamatic - upload your images
                                  :) Вы не против такого обращения с вашим рисунком?
                                    0
                                    Да нет, получилось очень даже ничего ))
                                    Хотя первый ваш вариант, мне больше по душе
                              0
                              Жаль, что для виртуального хостинга Яндекс.XML не подходит ввиду ограничений по числу запросов с IP и физической невозможности получить код доступа, если конкретный IP для этой же цели уже использован кем-то другим. Сделали бы в Яндексе JavaScript API, подобный гугловскому.
                                0
                                ммм… много работаю с я.иксмл, и думаю что для тех кто не пробывал ранее, лучше обратится к примерам на самом Я., без задней мысли, там просто реализованно по четче, примеров куча… ну и стиль кода мне там больше навицца)
                                  0
                                  почему бы вам не вклинить проект на nano.yandex.ru?
                                    0
                                    Зачем нужен поиск с ограничениями и чужой рекламой — если есть Sphinx?
                                    Мне лично не нравится — если 1001 человек ничего не получит в результатах поиска,
                                    как-то это не солидно.
                                      0
                                      Всегда приятнее часть ответственности переложить на другого :)
                                      К тому же, sphinx — это уже тяжёлая артиллерия, для простеньких сайтов его использовать просто нерационально. (оффтопик: а sphinx умеет добавлять элементы в индекс без полной его перестройки?)
                                      0
                                      смотрел доки на xml.yandex.ru и исходники, но так и не получилось запустить поиск с вашим классом по определённому сайту (куда только не пихал «<< host=mysite.ru»)

                                      подскажите?

                                      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                      Самое читаемое