Создание клиента поиска в виде консольного приложения на C#

Предупреждение

API Поиска Bing будут перенесены из Cognitive Services в службы Поиска Bing. С 30 октября 2020 г. подготовку всех новых экземпляров Поиска Bing необходимо будет выполнять в соответствии с процедурой, описанной здесь. API-интерфейсы Поиска Bing, подготовленные с помощью Cognitive Services, будут поддерживаться в течение следующих трех лет или до завершения срока действия вашего Соглашения Enterprise (в зависимости от того, какой период окончится раньше). Инструкции по миграции см. в статье о службах Поиска Bing.

В этом руководстве объясняется, как создать простое консольное приложение .NET Core, с помощью которого пользователи могут отправлять запросы в API Bing для поиска в Интернете и отображает ранжированные результаты.

В этом учебнике описаны следующие действия:

  • выполнение простого запроса к API Bing для поиска в Интернете;
  • отображение результатов запроса в порядке приоритета.

Предварительные требования

Для работы с этим руководством вам потребуется следующее:

Создание проекта консольного приложения

В Visual Studio создайте проект с помощью клавиш Ctrl+Shift+N.

В диалоговом окне Создать проект выберите Visual C# > Классический рабочий стол Windows > Консольное приложение (.NET Framework) .

Присвойте приложению имя MyConsoleSearchApp и нажмите кнопку ОК.

Добавление в проект пакета NuGet для JSON.NET

Json.NET позволяет работать с ответами JSON, которые возвращает API. Добавьте в проект этот пакет NuGet.

  • В обозревателе решений щелкните проект правой кнопкой мыши и выберите пункт Управление пакетами NuGet... .
  • На вкладке Обзор выполните поиск по Newtonsoft.Json. Выберите последнюю версию и щелкните Установить.
  • Нажмите кнопку ОК в окне Просмотреть изменения.
  • Закройте вкладку Visual Studio NuGet: MyConsoleSearchApp.

Добавление ссылки на System.Web

В этом руководстве используется сборка System.Web. Добавьте в проект ссылку на эту сборку.

  • В обозревателе решений щелкните правой кнопкой мыши Ссылки и выберите Добавить ссылку... .
  • Выберите Сборки > Платформа, затем прокрутите вниз и установите флажок System.Web.
  • Нажмите кнопку ОК.

Добавление необходимых операторов using

Чтобы работал код из этого руководства, нужны три дополнительных оператора using. Добавьте эти операторы после существующих операторов using в верхней части файла Program.cs:

using System.Web;
using System.Net.Http;

Предложение на ввод запроса

В обозревателе решений откройте Program.cs. Внесите изменения в метод Main():

static void Main()
{
    // Get the user's query
    Console.Write("Enter Bing query: ");
    string userQuery = Console.ReadLine();
    Console.WriteLine();

    // Run the query and display the results
    RunQueryAndDisplayResults(userQuery);

    // Prevent the console window from closing immediately
    Console.WriteLine("\nHit ENTER to exit...");
    Console.ReadLine();
}

Этот метод выполняет следующее:

  • предлагает пользователю ввести запрос;
  • вызывает RunQueryAndDisplayResults(userQuery) для выполнения запроса и отображения результатов;
  • ожидает ввода данных пользователем, чтобы окно консоли не закрывалось сразу после вывода.

Поиск результатов запроса с помощью API Bing для поиска в Интернете

Добавьте метод, который передает запрос в API и отображает результаты.

static void RunQueryAndDisplayResults(string userQuery)
{
    try
    {
        // Create a query
        var client = new HttpClient();
        client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "<YOUR_SUBSCRIPTION_KEY_GOES_HERE>");
        var queryString = HttpUtility.ParseQueryString(string.Empty);
        queryString["q"] = userQuery;
        var query = "https://api.cognitive.microsoft.com/bing/v7.0/search?" + queryString;

        // Run the query
        HttpResponseMessage httpResponseMessage = client.GetAsync(query).Result;

        // Deserialize the response content
        var responseContentString = httpResponseMessage.Content.ReadAsStringAsync().Result;
        Newtonsoft.Json.Linq.JObject responseObjects = Newtonsoft.Json.Linq.JObject.Parse(responseContentString);

        // Handle success and error codes
        if (httpResponseMessage.IsSuccessStatusCode)
        {
            DisplayAllRankedResults(responseObjects);
        }
        else
        {
            Console.WriteLine($"HTTP error status code: {httpResponseMessage.StatusCode.ToString()}");
        }
    }
    catch (Exception e)
    {
        Console.WriteLine(e.Message);
    }
}

Этот метод выполняет следующее:

  • создает HttpClient для отправки запроса к API поиска в Интернете;
  • задает заголовок HTTP Ocp-Apim-Subscription-Key, по которому Bing проверяет подлинность запроса;
  • выполняет запрос и использует JSON.net для десериализации результатов;
  • вызывает DisplayAllRankedResults(responseObjects) для отображения результатов в порядке приоритета.

Не забудьте задать правильное значение ключа подписки в параметре Ocp-Apim-Subscription-Key.

Отображение ранжированных результатов

Перед тем, как переходить к отображению результатов в порядке приоритета, давайте рассмотрим пример ответа на простой запрос поиска в Интернете:

{
    "_type" : "SearchResponse",
    "webPages" : {
        "webSearchUrl" : "https:\/\/www.bing.com\/cr?IG=70BE289346...",
        "totalEstimatedMatches" : 982000,
        "value" : [{
            "id" : "https:\/\/api.cognitive.microsoft.com\/api\/v7\/#WebPages.0",
            "name" : "Contoso Sailing Club - Seattle",
            "url" : "https:\/\/www.bing.com\/cr?IG=70BE289346ED4594874FE...",
            "displayUrl" : "https:\/\/contososailingsea...",
            "snippet" : "Come sail with Contoso in Seattle...",
            "dateLastCrawled" : "2017-04-07T02:25:00"
        },
        {
            "id" : "https:\/\/api.cognitive.microsoft.com\/api\/7\/#WebPages.6",
            "name" : "Contoso Sailing Lessons - Official Site",
            "url" : "http:\/\/www.bing.com\/cr?IG=70BE289346ED4594874FE...",
            "displayUrl" : "https:\/\/www.constososailinglessonsseat...",
            "snippet" : "Contoso sailing lessons in Seattle...",
            "dateLastCrawled" : "2017-04-09T14:30:00"
        },

        ...

        ],
        "someResultsRemoved" : true
    },
    "relatedSearches" : {
        "id" : "https:\/\/api.cognitive.microsoft.com\/api\/7\/#RelatedSearches",
        "value" : [{
            "text" : "sailing lessons",
            "displayText" : "sailing lessons",
            "webSearchUrl" : "https:\/\/www.bing.com\/cr?IG=70BE289346E..."
        }

        ...

        ]
    },
    "rankingResponse" : {
        "mainline" : {
            "items" : [{
                "answerType" : "WebPages",
                "resultIndex" : 0,
                "value" : {
                    "id" : "https:\/\/api.cognitive.microsoft.com\/api\/v7\/#WebPages.0"
                }
            },
            {
                "answerType" : "WebPages",
                "resultIndex" : 1,
                "value" : {
                    "id" : "https:\/\/api.cognitive.microsoft.com\/api\/v7\/#WebPages.1"
                }
            }

            ...

            ]
        },
        "sidebar" : {
            "items" : [{
                "answerType" : "RelatedSearches",
                "value" : {
                    "id" : "https:\/\/api.cognitive.microsoft.com\/api\/v7\/#RelatedSearches"
                }
            }]
        }
    }
}

Объект JSON rankingResponse (подробнее описан в документации) предоставляет правильный порядок отображения для результатов поиска. Он содержит одну или несколько следующих групп с учетом приоритета:

  • pole: Результаты поиска, которые должны отображаться наиболее заметным образом (например, над основной частью и боковой панелью).
  • mainline: Результаты поиска для отображения в основном поле.
  • sidebar: Результаты поиска для отображения на боковой панели. Если боковая панель отсутствует, эти результаты отображаются под основной частью.

JSON с ранжированным ответом может содержать одну или несколько этих групп.

Добавьте в файл Program.cs следующий метод для отображения результатов в порядке приоритета:

static void DisplayAllRankedResults(Newtonsoft.Json.Linq.JObject responseObjects)
{
    string[] rankingGroups = new string[] { "pole", "mainline", "sidebar" };

    // Loop through the ranking groups in priority order
    foreach (string rankingName in rankingGroups)
    {
        Newtonsoft.Json.Linq.JToken rankingResponseItems = responseObjects.SelectToken($"rankingResponse.{rankingName}.items");
        if (rankingResponseItems != null)
        {
            foreach (Newtonsoft.Json.Linq.JObject rankingResponseItem in rankingResponseItems)
            {
                Newtonsoft.Json.Linq.JToken resultIndex;
                rankingResponseItem.TryGetValue("resultIndex", out resultIndex);
                var answerType = rankingResponseItem.Value<string>("answerType");
                switch (answerType)
                {
                    case "WebPages":
                        DisplaySpecificResults(resultIndex, responseObjects.SelectToken("webPages.value"), "WebPage", "name", "url", "displayUrl", "snippet");
                        break;
                    case "News":
                        DisplaySpecificResults(resultIndex, responseObjects.SelectToken("news.value"), "News", "name", "url", "description");
                        break;
                    case "Images":
                        DisplaySpecificResults(resultIndex, responseObjects.SelectToken("images.value"), "Image", "thumbnailUrl");
                        break;
                    case "Videos":
                        DisplaySpecificResults(resultIndex, responseObjects.SelectToken("videos.value"), "Video", "embedHtml");
                        break;
                    case "RelatedSearches":
                        DisplaySpecificResults(resultIndex, responseObjects.SelectToken("relatedSearches.value"), "RelatedSearch", "displayText", "webSearchUrl");
                        break;
                }
            }
        }
    }
}

Этот метод выполняет следующее:

  • в цикле обрабатывает группы rankingResponse, которые содержит ответ;
  • отображает элементы каждой из групп, вызывая DisplaySpecificResults(...).

Добавьте в файл Program.cs следующие два метода:

static void DisplaySpecificResults(Newtonsoft.Json.Linq.JToken resultIndex, Newtonsoft.Json.Linq.JToken items, string title, params string[] fields)
{
    if (resultIndex == null)
    {
        foreach (Newtonsoft.Json.Linq.JToken item in items)
        {
            DisplayItem(item, title, fields);
        }
    }
    else
    {
        DisplayItem(items.ElementAt((int)resultIndex), title, fields);
    }
}

static void DisplayItem(Newtonsoft.Json.Linq.JToken item, string title, string[] fields)
{
    Console.WriteLine($"{title}: ");
    foreach( string field in fields )
    {
        Console.WriteLine($"- {field}: {item[field]}");
    }
    Console.WriteLine();
}

Эти методы работают совместно, чтобы вывести в консоль результаты поиска.

Выполнение приложения

Запустите приложение. Результат должен выглядеть следующим образом.

Enter Bing query: sailing lessons seattle

WebPage:
- name: Contoso Sailing Club - Seattle
- url: https://www.bing.com/cr?IG=70BE289346ED4594874FE...
- displayUrl: https://contososailingsea....
- snippet: Come sail with Contoso in Seattle...

WebPage:
- name: Contoso Sailing Lessons Seattle - Official Site
- url: http://www.bing.com/cr?IG=70BE289346ED4594874FE...
- displayUrl: https://www.constososailinglessonsseat...
- snippet: Contoso sailing lessons in Seattle...

...

Дальнейшие действия

Изучите дополнительные сведения об использовании ранжирования при отображении ответов.