Поиск по сайту на основе Яндекс.XML


Посмотреть как это будет выглядеть

В этой статье будет рассказано о том, как организовать качественный поиск по своему сайту с учётом морфологии русского языка. Полноценным решением поставленной задачи будет использование службы Яндекс.XML от крупнейшей российской поисковой системы Яндекс.

Работать с XML-выдачей Яндекса мы будем на языке C# в рамках платформы ASP.NET, используя стандартные (начиная с .Net Framework 2.0) модули System.Xml и System.Net.

Прежде чем наш скрипт начнёт обращаться к Яндексу с запросами, нужно зарегистрировать по ссылке http://xml.yandex.ru/ip.xml IP-адрес сайта, на котором будет работать скрипт.

Теперь можно начинать задавать XML-запросы, в которых помимо запроса и области поиска (определённый сайт или регион), можно задавать различные группировки и сортировки.

В ответ программа получает результаты поиска в формате XML, которые можно интерпретировать самостоятельно, или отображать в своем дизайне при помощи XSLT.

Приступим непосредственно к программированию.
Создаём web-форму, в ней размещаем два текстовых поля (для запроса и для сайта, по которому будет производиться поиск) и кнопку для начала поиска.

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="YandexSearch.aspx.cs" Inherits="YandexSearch" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

 

<html xmlns="http://www.w3.org/1999/xhtml">

<head runat="server">

    <title>Поиск по сайту</title>

</head>

<body>

    <form id="form1" runat="server">

        <h1>Поиск по сайту на основе Яндекс.XML</h1><br>

        <asp:Panel ID="pnlSiteSearch" runat="server" DefaultButton="btnSeach">

            <table>

                <tr>

                    <td>

                        <asp:Label ID="lblSite" runat="server" Text="Поиск по сайту: " AssociatedControlID="txtSite"></asp:Label>

                     </td>

                     <td>
                         <asp:TextBox ID="txtSite" runat="server" Text="www.yandex.ru"></asp:TextBox>

                     </td>

                 </tr>

                 <tr>

                     <td>

                         <asp:Label ID="lblQuery" runat="server" Text="Запрос: " AssociatedControlID="txtQuery"></asp:Label>

                     </td>
                     <td>
                         <asp:TextBox ID="txtQuery" runat="server" Text="Яндекс"></asp:TextBox>
                     </td>
                 </tr>
                 <tr>
                     <td></td>
                     <td><asp:Button ID="btnSeach" runat="server" Text="Искать" onclick="btnSeach_Click" /></td>
                 </tr>
             </table>
         </asp:Panel>

         <asp:Literal ID="ltlResults" runat="server"></asp:Literal>

        
        <
asp:Panel ID="pnlPager" runat="server">

            <asp:LinkButton ID="lnkPrev" runat="server" onclick="lnkPrev_Click" Visible="false">предыдущая</asp:LinkButton>

            <asp:Label ID="lblCurrentPosition" runat="server"></asp:Label>

            <asp:LinkButton ID="lnkNext" runat="server" onclick="lnkNext_Click" Visible="false">следующая </asp:LinkButton>

        </asp:Panel>

     </form>
 </body>
 </html>

 

Код страницы с обработчиками нажатия кнопки и переключателя страниц:

using System;

using System.Web.UI; 

using System.Net;

using System.IO;

using System.Xml;

using System.Text;

using System.Text.RegularExpressions;

 

public partial class YandexSearch : System.Web.UI.Page

{

    const int DOCS_ON_PAGE = 10; // кол-во отображаемых документов результатов поиска на одной странице

    int PageIndex // номер текущей страницы в переключателе страниц

    {

        get { return ViewState["PageIndex"] == null ? 0 : Convert.ToInt32(ViewState["PageIndex"]); }

        set { ViewState["PageIndex"] = value; }

    }

    protected void btnSeach_Click(object sender, EventArgs e) // обработчик нажатия кнопки

    {

        DoSearch(txtQuery.Text, txtSite.Text, this.PageIndex);

    }

    protected void lnkPrev_Click(object sender, EventArgs e) // обработчик нажатия гиперссылки "далее"

    {

        DoSearch(txtQuery.Text, txtSite.Text, --this.PageIndex);

    }

    protected void lnkNext_Click(object sender, EventArgs e) // обработчик нажатия гиперссылки "назад"

    {

        DoSearch(txtQuery.Text, txtSite.Text, ++this.PageIndex);

    }

 

    /// <summary>

    /// Функция поиска

    /// </summary>

    /// <param name="searchQuery">поисковый запрос</param>

    /// <param name="hostName">адрес сайта, по которому будет производиться поиск</param>

    /// <param name="pageIndex">номер запрашиваемой страницы результатов поиска</param>

    public void DoSearch(string searchQuery, string hostName, int pageIndex)

    {

        // -------- отправляем запрос на сервис xmlsearch.yandex.ru --------

        HttpWebRequest objRequest = (HttpWebRequest)WebRequest.Create("http://xmlsearch.yandex.ru/xmlsearch");

        objRequest.Method = "POST";

        objRequest.ContentType = "application/xml";

        using (Stream str = objRequest.GetRequestStream())

        {

            using (XmlWriter writer = XmlWriter.Create(str)) // формируем запрос

            {

                writer.WriteStartDocument();

                writer.WriteStartElement("request");

                writer.WriteElementString("query", searchQuery + "<<(site:" + hostName + ")");

                if (pageIndex > 0)

                    writer.WriteElementString("page", pageIndex.ToString());

                writer.WriteElementString("maxpassages", "5");

                writer.WriteRaw("<groupings><groupby attr=\"\" mode=\"flat\" groups-on-page=\"" + DOCS_ON_PAGE.ToString() + "\" docs-in-group=\"1\" /></groupings>");

                writer.WriteEndElement();

                writer.WriteEndDocument();

            }

        }


        // -------- получаем ответ с сервиса xmlsearch.yandex.ru --------
        XmlDocument xDocument = new XmlDocument();
        using (HttpWebResponse myResponse = (HttpWebResponse)objRequest.GetResponse()) // формируем запрос

        {
       
xDocument.Load(myResponse.GetResponseStream());
        }

 

        // -------- смотрим нет ли ошибок --------

        XmlNode errNode = xDocument.SelectSingleNode("yandexsearch/response/error");

        if (errNode != null)

        {

            if (errNode.Attributes["code"] != null && errNode.Attributes["code"].Value == "15")

                this.ltlResults.Text = "Искомая комбинация слов нигде не встречается";

            else

                this.ltlResults.Text = "Ошибка. Код: " + errNode.Attributes["code"].Value;

            return;

        }


        // -------- определяем сколько документов нашлось --------

        XmlNode foundNode = xDocument.SelectSingleNode("yandexsearch/response/found[@priority='all']");

        if (foundNode == null)

        {

            this.ltlResults.Text = "Не удаётся определить кол-во найденныйх документов";

            return;

        }

 

        int totalResults = Convert.ToInt32(foundNode.InnerXml); // кол-во найденных документов

        int totalPages = (int)Math.Ceiling((decimal)totalResults / DOCS_ON_PAGE); // кол-во страниц с результатами

 

        // -------- формируем результаты поиска --------

        StringBuilder sb = new StringBuilder();

        sb.AppendFormat("<span>Результаты поиска для \"{0}\"</span>", Server.HtmlEncode(searchQuery));

        int c = 0;

        sb.Append("<ul>");

        foreach (XmlNode node in xDocument.SelectNodes("yandexsearch/response/results/grouping/group/doc"))

        {

            sb.AppendFormat("<li style=\"margin:20px 0;\"><a class=\"Title\" href=\"{1}\" style=\"font-size:120%\">{0}</a>",

                node.SelectSingleNode("title") != null ? hlwordsHighlight(node.SelectSingleNode("title").InnerXml) : node.SelectSingleNode("url").InnerXml,

                node.SelectSingleNode("url").InnerXml

                );

            sb.Append("<ul>");

            XmlNode passagesNode = node.SelectSingleNode("passages");

            if (passagesNode != null)

                foreach (XmlNode passage in passagesNode.SelectNodes("passage"))

                    sb.AppendFormat("<li>{0}</li>", hlwordsHighlight(passage.InnerXml));

            sb.Append("</ul>");

            sb.AppendFormat("<span class=\"Url\" style=\"color:#060;\">{0}&nbsp;&nbsp;(&nbsp;{1}&nbsp;байт)</span></li>", node.SelectSingleNode("url").InnerXml, node.SelectSingleNode("size").InnerXml);

            c++;

        }

        sb.Append("</ul>");

        ltlResults.Text = sb.ToString();

        if (c < DOCS_ON_PAGE - 1)

        {

            totalResults = this.PageIndex * DOCS_ON_PAGE + c;

            totalPages = this.PageIndex;

        }


        // -------- Настраиваем переключатель страниц --------

        this.lnkPrev.Visible = (pageIndex > 0);

        this.lnkNext.Visible = (pageIndex < totalPages - 1);

 

        this.lblCurrentPosition.Text = string.Format("<span>Результаты поиска {0}-{1}</span>",

            (pageIndex * DOCS_ON_PAGE) + 1,

            Math.Min((pageIndex + 1) * DOCS_ON_PAGE, totalResults)

            );

    }

 

    /// <summary>

    /// Функция подсветки найденных результатов

    /// </summary>

    /// <param name="text">Текст в котором обозначены найденные фрагменты поискового запроса тегами <hlword></param>

    /// <returns>Выделяет найднные фрагменты тегами strong</returns>

    public static string hlwordsHighlight(string text)

    {

        text = Regex.Replace(text, "<hlword[^>]*>", "<strong>", RegexOptions.IgnoreCase | RegexOptions.Compiled);

        text = Regex.Replace(text, "</hlword>", "</strong>", RegexOptions.IgnoreCase | RegexOptions.Compiled);

        return text;

    }

}



Скачать архив исходного кода получившейся страницы.
 
Есть вопросы?
Задавайте:

info@svarga.biz