キャスレーコンサルティング 技術ブログ

ウェブスクレイピング処理@C#【入門編】

Posted on 09月 30, 2015

こんにちは、SD部の江本です。
今回は、C#によるスクレイピング処理について記述したいと思います。

構成

  • はじめに
  • 何か活用できるの?
  • 注意事項
  • 環境
  • 実際に取得してみよう!
  • 終わりに

はじめに

ネット社会になって随分経ちますが、ネット上には無数の情報が眠っています。
スマホ、タブレット、PCと色々な方法でネットにアクセスできる端末が増えてきていますね。

それらの端末が各サイトへアクセスし、どのように情報を取得しているのか?
また、それらの情報を取得して、データの分析や解析等を実施してみたいなと思った人はいらっしゃいませんか?

その中でも今回は、ウェブスクレイピングという技術です。
簡単に説明しますと。。。

ウェブスクレイピングとは

Webスクレイピングとは、WebサイトからWebページのHTMLデータを収集して、

特定のデータを抽出、整形し直すことである。

ウェブスクレイピング – Wikipedia

WEBサーバと通信してHTMLを取得してみるという試みです。
この技術を知った当時、少し調べてみたらPHPでのスクレイピング処理が数多く検索にHITしました。
今回は、そのスクレイピング処理をC#で書いてみたい!と思い企画してみました。

本稿は、DB周りなどの処理も書かないで、基本的なところであるURLからHTML取得。

取得したHTMLから特定の情報を取得する、というところをゴールとして記載しようと思います。

何か活用できるの?

ネット上から情報を取得できるので、色々と活用方法は色々あると思います。
普段私達が利用している情報をそのまま取得できるわけですからね。
今まで勉強のため作ったことがある機能は、以下のような機能です。

  • URLが登録してある特定のサイトからHTMLを取得し保存する。次回取得時に、前回保存したHTMLと比べて差異があるかどうかでサイトが更新されているか確認を取ることができます。
  • 会社の役職者が使用しているグループウェアに一定周期でアクセスし、そこから承認業務が必要な項目が存在した場合に「承認業務が溜まってますよ!」と教えてくれるプログラムです。

勿論上記以外にも色々と使用用途はありますが、趣味のコーディングでここまでやってみました。

注意事項

本稿で記述しているプログラムは、実際にサーバにアクセスを行います。
一定以上のアクセスを行うとサーバに負荷がかかる可能性がありますので、ご使用の際は注意してください。
また、情報の取り扱いには十二分に気をつけてください。

環境

本稿は以下の環境で構築を行いました。

  • Windows7 Pro SP1
  • Visual Studio Community 2015
  • .NET Framework 4.5.2
  • C#

実際に取得してみよう!

URLにアクセスするということで、今回はキャスレーコンサルティングのHPを対象に行ってみたいと思います。

http://www.casleyconsulting.co.jp/

それでは実際に作成してみましょう。
以下の順序で解説を行っていきます。

  1. プロジェクトの作成
  2. HTML取得
  3. Title取得
  4. 動作確認

1.プロジェクトの作成

まずプロジェクトの作成を行いましょう。
VisualStudioを起動して、スタートページにある新しいプロジェクトをクリックします。
新しいプロジェクトのウィンドウが開きますので、WindowsFormApplicationのプロジェクトを作成します。
C#スクレイピング_Project作成
システムとしては、画面上の開始ボタン押下でURLが記載されているテキストボックスからアクセス先のURLを取得し、HTMLを取得します。
取得したHTMLとHTML内で定義されているTitleを画面に表示するというシステムを作成します。

本稿では、以下のような画面構成で作成を行います。
C#スクレイピング_画面イメージ

2.HTML取得

プロジェクト内にスクレイピングのサンプルクラスを作成します。
プロジェクト名上で、右クリックし、「追加(D)」⇒「クラス(C)」をクリックします。
クラス作成のウィンドウで、「SampleScraping.cs」の名前でクラスを作成してください。
ここに以下のメソッドを追加します。

using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Net;
using System.Text.RegularExpressions;

namespace WindowsFormsApplication
{
    class SampleScraping
    {
        /// <summary>
        /// 引数urlにアクセスした際に取得できるHTMLを返します。
        /// </summary>
        /// <param name="url">URL(アドレス)</param>
        /// <returns>取得したHTML</returns>
        public string GetHtml(string url)
        {
            // 指定されたURLに対してのRequestを作成します。
            var req = (HttpWebRequest)WebRequest.Create(url);

            // html取得文字列
            string html = "";

            // 指定したURLに対してReqestを投げてResponseを取得します。
            using (var res = (HttpWebResponse)req.GetResponse())
            using (var resSt = res.GetResponseStream())
            // 取得した文字列をUTF8でエンコードします。
            using (var sr = new StreamReader(resSt, Encoding.UTF8))
            {
                // HTMLを取得する。
                html = sr.ReadToEnd();
            }

            return html;
        }
    }
}

ソースの流れとしては、以下のような形になります。

  1. Requestを作成します。(17行目)
  2. Requestを投げてServerからResponseを取得します。(25行目)
  3. ResponseからStreamを取得し、UTF8の文字列に変換します。(26行目~31行目)
  4. HTMLの文字列を戻り値として返します。(34行目)

このソース量でHTMLを取得することができます。

3.Title取得

それでは、次にHTMLのタイトルを取得してみましょう。
今回は、正規化表現を使用した取得方法を試してみます。

まず、取得したHTMLのTitle部分を見てみましょう

<title>キャスレーコンサルティング株式会社 | お客様と社会、従業員すべてに共通した価値をもたらすビジネスとサービスをITで創り出すこと、それが私たちキャスレーコンサルティングのビジョンです。</title>

両端のtitleタグを抜いた文言を取得できれば成功です。
先ほどのSampleScrapingクラスに以下のメソッドを追加します。


        /// <summary>
        /// 正規化表現を使用してHTMLからタイトルを取得します。
        /// </summary>
        /// <param name="html">HTML文字列</param>
        /// <returns>HTML文字列から取得したタイトル</returns>
        public string GetTitle(string html)
        {

            // 正規化表現
            // 大文字小文字区別なし       : RegexOptions.IgnoreCase
            // 「.」を改行にも適応する設定: RegexOptions.Singleline
            var reg = new Regex(@"<title>(?<title>.*?)</title>",
						 RegexOptions.IgnoreCase | RegexOptions.Singleline);

            // html文字列内から条件にマッチしたデータを抜き取ります。
            var m = reg.Match(html);

            // 条件にマッチした文字列内からKey("title部分")にマッチした値を抜き取ります。
            return m.Groups["title"].Value;

        }

ソースの流れとしては、以下のような形になります。

  1. 正規表現の文字列を作成します。(12行目)
  2. 正規表現を元にHTML内を検索し、該当の文字列を取得します。(16行目)
  3. タイトル部分を抜き取った文字列内からtitleタグを抜いた文字列を取得します。(19行目)

これだけで、タイトルの取得処理が完了します。

4.動作確認

それでは実際に動かしてみましょう。
スクレイピング処理を実装したクラスを使用してみましょう。
画面側に作成した開始ボタンをダブルクリックすると、Form1クラスにボタン押下のアクションメソッドが実装されます。
そこに取得処理を入れてみましょう。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 開始ボタンクリック
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnStart_Click(object sender, EventArgs e)
        {
            // 処理中に「取得中」とラベル表示します。
			// 予めURLのテキストボックス下に無記名のラベルを作成しておきます。
			// (Name)をlblViewにしておいてください。
            lblView.Visible = true;			// 可視化
            lblView.Text = "取得中";		// 「取得中」の文字列を表示することで処理中であることを明記します。
            lblView.BringToFront();			// Objectを最善面に移動します。
            lblView.Update();				// 表示を更新します。

            // 今回サンプルで作成を行ったクラスをインスタンス化します。
            var scr = new SampleScraping();

            // 画面上からHTMLを取得するサイトのURLを取得します。
            string url = txtUrl.Text;

            // htmlを取得するメソッドを実行し、画面描画します。
            string html = scr.GetHtml(url);
            txtHtml.Text = html;

            // 取得したHTML内からタイトルを取得します。
            string title = scr.GetTitle(html);
            txtTitle.Text = title;

            // 「取得中」の文言を不可視にします。
            lblView.Visible= false;
        }
    }
}

これで準備は完了です。
それでは実行してみましょう。

まずは、実行時の画面です。

C#スクレイピング_準備完了

開始ボタンを押下すると「取得中」と表示されます。

C#スクレイピング_取得中

以下のような感じで表示されたら取得成功です。

C#スクレイピング_処理完了

終わりに

今回は入門編ということで、基礎的なところを説明していきました。
プログラムを触ったことがある人であれば、ご理解頂ける内容だったのかなと思います。
簡単なプログラムではありますが、
この先に見える可能性などを考えるとわくわくしてくる技術だと思っていただければ幸いです。
もう少し突っ込んだ内容に入っていくとパーサーを使用した動的な取得など
色々工夫できる内容は多いと思いますので、次回また技術ブログでお会い出ればと思います。


採用情報

  • Profile
    キャスレーコンサルティングの技術ブログです。
    当社エンジニアが技術面でのTips、技術系イベント等についてご紹介いたします。
  • CSV社長ブログ
  • チーム・キャスレーブログ