Поиск по сайту на основе Яндекс.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} ( {1} байт)</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;
}
}
Скачать архив исходного кода получившейся страницы.