アレアレ

お役立ち情報、お悩み解決情報を発信!

visual studio code

.NET CoreアプリでHTMLを取得しパースする方法

.NET CoreアプリでHTMLを取得しパースする方法

今回は、.NET Coreアプリ向けにオリジナルのクローラーをC#で作りたい人にお伝えしたいお役立ち情報です。

.NET Coreでは、System.Net.Http.HttpClientというクラスを使うことで、指定したURLからHTMLを取得することができます。

そして、AngleSharpというHTMLパーサーを利用して、そのHTMLをjQueryのようなセレクタを利用して、解析することができます。

そこで今回は、HttpClientとAngleSharpを利用して、アップルの日本語公式サイト(http://apple.com/jp/)から、HTMLを取得し、aタグ内のhrefタグを列挙する簡単なコンソールアプリのサンプルをご紹介します。

開発環境

では、まず、開発環境からご紹介します。

  • OS: macOS Sierra バージョン 10.12
  • .Net Core: 1.0.0-preview3-003612

以上の通り、私の開発環境ですが、Macを利用しています。ですが、今回のサンプルは、クロスプラットフォームで動作する.Net Coreなので、Linuxでも、Windowsでも同様に動作します。

また、この記事では、Macでの.Net Core向けのコンソールアプリの作り方について、解説しません。その方法は、Microsoftが公開しているドキュメントに詳しく解説されているからです。

なので、この記事では、yoコマンドで.Net Coreアプリのプロジェクトのテンプレートを生成できる環境が整っている前提とします。

project.json

それでは、本題に入ります。まず、yoコマンド(ターミナルで「yo aspnet」)で.Net Coreのコンソールアプリをプロジェクトを生成します。ここでは、ParseHtmlSampleというプロジェクト名で、そのプロジェクトを生成したとします。

次に、生成したプロジェクトで、HTMLパーサーとなるAngleSharpを利用するために、project.jsonを次のように修正します。

{
  "version": "1.0.0-*",
  "buildOptions": {
    "emitEntryPoint": true
  },

  "dependencies": {
    "Microsoft.NETCore.App": {
      "type": "platform",
      "version": "1.0.0"
    },
    <strong>"AngleSharp": "0.9.8.1"</strong>,
    "System.Text.Encoding.CodePages": "4.0.1"
  },

  "frameworks": {
    "netcoreapp1.0": {
      "imports": "dnxcore50"
    }
  },

  "tooling": {
    "defaultNamespace": "ParseHtmlSample"
  }
}

ポイントは、dependenciesに「”AngleSharp”: “0.9.8.1”」を追加している箇所です。こうすることで、このコンソールアプリから、HTMLパーサーが利用できるようになります。

また詳細は後述しますが、取得対象のサイトが返す文字コードがshift-jisの場合は、「”System.Text.Encoding.CodePages”: “4.0.1”」も、利用することになります。

Program.cs

続いて、Program.csを修正し、メインの処理を記述します。先にコードをご紹介すると次の通りです。

using System;
using System.Threading.Tasks;
using System.Text;
using System.Net.Http;
using AngleSharp.Parser.Html;

namespace ParseHtmlSample
{
    public class Program
    {
        public static void Main(string[] args)
        {
            //レスポンスの文字コードがshift_jisの場合は、
            //次のコメントを外さないとHttpClientのGetAsyncでエラーになる
            //Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

            //メイン処理の実行
            MainAsync(args).Wait();

        }

        //HttpClientのGetAsyncメソッドをawaitで実行するためのメイン処理
        public static async Task MainAsync(string[] args){
            
            //指定したURLのHTMLを取得する
            var url = "http://apple.com/jp/";
            var client = new HttpClient();
            var response = await client.GetAsync(url);
            var html = await response.Content.ReadAsStringAsync();
            
            //HTMLをパーサーに読み込む
            var parser = new HtmlParser();
            var doc = parser.Parse(html);

            //HTMLの中からaタグのhref属性を出力する
            foreach(var item in doc.QuerySelectorAll("a")){
                Console.WriteLine(item.Attributes["href"].Value);
            }
        }
    }
}

このサンプルですが、ソースのコメントを読めば、処理内容はわかりますよね。なので、その詳細は省き、そのポイントのみ解説します。

まず、Mainメソッドの最初では、「Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);」の行がコメントになっています。

今回のサンプルのままであれば、この行はコメントのままで動きます。ただ、取得するURL次第では、コメントを外す必要があります。例えば、文字コードがshift-jisで返されるGoogleの日本語サイトの検索結果などです。

このように、shift-jisで文字コードが返されるサイトのHTMLを取得したい場合は、上記のコメントを外す必要があります。

続いて、今回のサンプルでは、わざわざ「public static async Task MainAsync(string[] args)」と、非同期のメインメソッドを新たに用意しています。

これは、非同期処理となるHttpClientのGetAsyncメソッドをawaitを使って、同期的に実行したいがためにこのようにしています。今回のサンプルでは、HTMLを非同期で取得するのではなく、待ってでも同期処理で取得したかったんですね。

なので、このような構成になっています。

HTMLが取得できたら、あとは簡単です。AngleSharpのHtmlParserクラスを利用し、それを解析するだけだからです。

HtmlParserクラスでは、QuerySelectorAllメソッドやQuerySelectorメソッドなどを利用して、jQueryのセレクタのように取得したHTMLのDOM要素を解析することができます。

QuerySelectorAllメソッドでは、指定したセレクタに該当するオブジェクトが複数返されます。今回では、aタグ全てを取得し、そのaタグのhref属性の値を出力しています。

ちなみにこの例では、単純に”a”とセレクタを指定していますが、もちろん「#」始まりのIDで指定したり、「.」始まりのクラス名で指定したりすることができます。

Return Top