0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Bing Search v7 クライアント ライブラリがないので、実装してみた

Last updated at Posted at 2020-11-21

はじめに

Azure Cognitive Services のカテゴリの一つに Web 検索があります。Web 検索では、Microsoft 社の Web 検索エンジンである Bing の検索を API 経由で利用できる Bing Search API がありましたが、これが、2020 年 10 月 30 日以降、利用できなくなったようです。
image.png
これ以前に、Azure Cognitive Services 内で Bing Search をインスタンス化している場合は、以降 3 年間は利用できるようですが、Azure Cognitive Services の Bing Search を新規に作成、利用することはできなくなりました。

今後、新規に Bing Search API を利用するには、Azure マーケットプレイスにある "Bing Search v7" を利用します。公式ページでも新規利用時のサービス有効化方法として、以下のページが案内されています。

これまでとの変更点としては、Bing Search API のエンドポイントが、以下のように変更されました。ドメインの cognitive 部分が、bing に変更されています。

.NET から、Bing Search API を呼び出す場合は、SDK(クライアント ライブラリ) が利用できました。WebSearch を行いたい場合は、"Microsoft.Azure.CognitiveServices.Search.WebSearch" というライブラリが NuGet 経由で入手可能で、これを使って非常に簡単に、Bing Search API を利用できたのですが、2020 年 11 月 21 日時点では、新しいエンドポイントに対して、このライブラリが正しく動作しません。
現状では、Bing Search API クライアント ライブラリの最終更新日は、2018/03/22 となっており、今回の移行にあわせたクライアント ライブラリの更新が行われていないようでした。
image.png

よって、今回は、Bing Search API をクライアント ライブラリを使わず、利用する方法を説明したいと思います。HttpClient で、直接 API をコールします。今回は、.NET 5 を使用しましたが、.NET Core 3.1 でも動作すると思います。

Bing Search v7 の有効化

Azure ポータルの [リソースの作成] から、"bing search" を検索し、[Bing Search v7] を選択して、Bing Search のインスタンスを作成します。
image.png
価格レベルについては、以下のサイトに記載があります。無料の Free も選択できて、1,000 トランザクション/月まで利用が可能です。

Bing Search のインスタンスが作成されたら、[キーとエンドポイント] を選択し、[キー 1] または、[キー 2] の文字列をコピーしておきます。このキーは、後ほど、API 呼び出しの際に、HTTP ヘッダーに入れて使用します。
image.png

BingClient クライアント ライブラリの実装

以降で、.NET Core コンソール アプリ(.NET 5)で、実装を行っていきます。
まず、BingClient クラスと、検索結果を格納する各クラスを定義します。

BingClient.cs

public class BingClient
{
    // Web ページ検索結果
    public class WebPage
    {
        public string Name;
        public string Url;
        public string Snippet;
        public DateTimeOffset DateLastCrawled;
    }

    // 画像検索結果
    public class Image
    {
        public string Name;
        public string ThumbnailUrl;
        public string ContentUrl;
        public DateTimeOffset DatePublished;
    }

    // 動画検索結果
    public class Video
    {
        public string Name;
        public string ThumbnailUrl;
        public string ContentUrl;
        public string Description;
        public string Publisher;
        public string Creator;
        public long? ViewCount;
        public DateTimeOffset DatePublished;
    }
}

次に、BingClient クラスのプライベートフィールドとコンストラクタを実装します。コンストラクタでは、Bing Search API のサブスクリプション キーを受け取りフィールドに保存しておきます。
また、HTTP 要求のために、HttpClient のインスタンスもフィールドに保存しておきます。

BingClient.cs

public class BingClient
{
    ....
    
    private static readonly HttpClient _httpClient = new HttpClient();

    private readonly string _endpoint = "https://api.bing.microsoft.com/v7.0";
    private readonly string _subscriptionKey = null;

    public BingClient(string subscriptionKey)
    {
        this._subscriptionKey = subscriptionKey;
    }
}

次に、BingClient クラスに各検索を実行するメソッドを実装していきます。レスポンスは、JSON で返ってきますので、Json.NET で処理します。コードを実装する前に、Json.NET(Newtonsoft.Json) を NuGet パッケージでインストールしておいてください。
先に、Search メソッドで、各検索要求の共通部分を実装しておきます。

BingClient.cs

public class BingClient
{
    ....

    private async Task<dynamic> Search(string url, string subscriptionKey)
    {
        HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, new Uri(url));
        request.Headers.Add("Ocp-Apim-Subscription-Key", subscriptionKey);

        HttpResponseMessage response = await _httpClient.SendAsync(request);
        response.EnsureSuccessStatusCode();

        string responseString = await response.Content.ReadAsStringAsync();
        dynamic json = JsonConvert.DeserializeObject<dynamic>(responseString);

        return json;
    }
}

次に、Web ページ検索を実行する SearchWeb メソッドを実装します。引数に、検索キーワード、マーケットコード、検索結果数をとります。
マーケットコードは、Market and language codes used by Bing Web Search API に定義があります。
また、検索結果の各プロパティは、最小限のものを入れていますので、必要に応じて、Web Search API v7 response objects
の "WebPage" を参照して、クラス、処理を拡張してください。

BingClient.cs

public class BingClient
{
    ....

    public async Task<IEnumerable<WebPage>> SearchWeb(string keyword, string market = "ja-JP", int resultCount = 10)
    {
        string endpoint = $"{_endpoint}/search";
        string url = $"{endpoint}?q={Uri.EscapeDataString(keyword)}&mkt={market}&responseFilter=Webpages&count={resultCount}";

        dynamic json = await this.Search(url, _subscriptionKey);

        var webPages = (json.webPages.value as IEnumerable<dynamic>).Select(page =>
            new WebPage()
            {
                Name = page.name,
                Url = page.url,
                Snippet = page.snippet,
                DateLastCrawled = DateTime.SpecifyKind(page.dateLastCrawled.Value, DateTimeKind.Utc),
            });

        return webPages;
    }
}

同様に、画像検索、動画検索も実装していきます。
画像検索の結果の各プロパティの定義は、Image Search APIs v7 response objects の Image に、動画検索の結果の各プロパティは、Video Search APIs v7 response objects
の Video を参照してください。

BingClient.cs

public class BingClient
{
    ....

    public async Task<IEnumerable<Image>> SearchImage(string keyword, string market = "ja-JP", int resultCount = 10)
    {
        string endpoint = $"{_endpoint}/images/search";
        string url = $"{endpoint}?q={Uri.EscapeDataString(keyword)}&mkt={market}&count={resultCount}";
            
        dynamic json = await this.Search(url, _subscriptionKey);

        var images = (json.value as IEnumerable<dynamic>).Select(img => 
            new Image()
            {
                Name = img.name,
                ThumbnailUrl = img.thumbnailUrl,
                ContentUrl = img.contentUrl,
                DatePublished = DateTime.SpecifyKind(img.datePublished.Value, DateTimeKind.Utc),
            });

        return images;
    }

    public async Task<IEnumerable<Video>> SearchVideo(string keyword, string market = "ja-JP", int resultCount = 10)
    {
        string endpoint = $"{_endpoint}/videos/search";
        string url = $"{endpoint}?q={Uri.EscapeDataString(keyword)}&mkt={market}&count={resultCount}";

        dynamic json = await this.Search(url, _subscriptionKey);

        var videos = (json.value as IEnumerable<dynamic>).Select(vdo =>
            new Video()
            {
                Name = vdo.name,
                ThumbnailUrl = vdo.thumbnailUrl,
                ContentUrl = vdo.contentUrl,
                Description = vdo.description,
                Publisher = vdo.publisher?[0]?.name,
                Creator = vdo.creator?.name,
                ViewCount = vdo.viewCount,
                DatePublished = DateTime.SpecifyKind(vdo.datePublished.Value, DateTimeKind.Utc),
            });           

        return videos;
    }

BingClient クライアント ライブラリの利用

実装した BingClient クライアント ライブラリを利用します。
"yourKey" には、先に Azure ポータルで有効化した Bing Search v7 のキーを設定してください。

Program.cs

class Program
{
    static async Task Main(string[] args)
    {
        string subscriptionKey = "<yourKey>";            
        string keyword = "猫";

        BingClient bingClient = new BingClient(subscriptionKey);

        var webPages = await bingClient.SearchWeb(keyword);
        webPages.ToList().ForEach(w => 
        {
            Console.WriteLine($"ページ タイトル: {w.Name}");
            Console.WriteLine($"概要: {w.Snippet}");
            Console.WriteLine($"URL: {w.Url}");
            Console.WriteLine();
        });            

        var images = await bingClient.SearchImage(keyword);
        images.ToList().ForEach(img =>
        {
            Console.WriteLine($"画像タイトル: {img.Name}");
            Console.WriteLine($"URL: {img.ContentUrl}");
            Console.WriteLine();
        });

        await Task.Delay(1000);

        var videos = await bingClient.SearchVideo(keyword);
        videos.ToList().ForEach(v =>
        {
            Console.WriteLine($"動画タイトル: {v.Name}");
            Console.WriteLine($"概要: {v.Description}");
            Console.WriteLine($"サムネイル URL: {v.ThumbnailUrl}");
            Console.WriteLine($"URL: {v.ContentUrl}");
            Console.WriteLine($"視聴数: {v.ViewCount}");
            Console.WriteLine();
        });

        var news = await bingClient.SearchNews(keyword);
        news.ToList().ForEach(n =>
        {
            Console.WriteLine($"ニュース タイトル: {n.Name}");
            Console.WriteLine($"概要: {n.Description}");
            Console.WriteLine($"サムネイル URL: {n.ThumbnailUrl}");
            Console.WriteLine($"URL: {n.Url}");                
            Console.WriteLine();
        });

        Console.ReadKey();
    }
}

実行結果は以下のようになります。
image.png

完全なコードは、以下の GitHub リポジトリに登録してあります。

参考サイト

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?