「モンスター社員の教科書」を作りました!

【C#】正規表現で文字列を抽出。コード例で解説します

C#
当サイトはアフィリエイト広告を利用しています

こんにちは、ひつじ先輩です。

C#で正規表現を使い、文字列から任意のパターンを抽出します。

 

とくに、スクレイピングをやりたい人には役立つはずです。

  1. サイトのソースコードを取得
  2. 文字列から欲しい部分を抽出

がスクレイピングの流れ。

 

この記事では、2の部分について書きます。

C#で正規表現のコード

static List<string> extractProxy(string source)
{
    //抽出結果をいれるためのリスト
    List<string> proxies = new List<string>();

    //抽出したい文字列を正規表現で書く
    Regex r = new Regex(@"class=""."">(\d.*?)</a></li>", RegexOptions.IgnoreCase | RegexOptions.Singleline);

    //正規表現と入力を比較。一致した文字列をリストに入れる。
    MatchCollection mc = r.Matches(source);

    //正規表現のための特殊なリスト型から普通の文字列リストへコピー
    foreach (Match m in mc) proxies.Add(m.Groups[1].Value);

    return proxies;
}
コードの先頭、usingのところに「System.Text.RegularExpressions」の追加が必要

 

  1. 文字列が入力される
  2. 正規表現でマッチした部分を抽出
  3. 当てはまる文字列をリストで返す

をやっています。

 

具体的には、プロキシのリストをふくむHTMLソース(string source)からプロキシリストを抽出してます。

 

HTMLをよく見る

正規表現で欲しい部分だけ抽出するため、まずパターンを見つけます。

 

取ってきたソースを見たとき、

<a title=”AF” onMouseOver=”s(‘DE’,’mx1.flintvpscoin.com’)” onMouseOut=”d()” class=”A”>51.68.92.17:8080</a></li>

<a title=”AF” onMouseOver=”s(‘AF’,’mail2.aitek.ru’)” onMouseOut=”d()” class=”B”>210.61.46.165:3128</a></li>

<a title=”AF” onMouseOver=”s(‘RU’,’ip-fmtc-jkt.polaris.net.id’)” onMouseOut=”d()” class=”A”>212.243.175.126:80</a></li>

といった表現が連続していたとします。

上記はcybersyndromeの例。現在はスクレイピング対策されている

 

HTMLソースのこの部分で、サイト上にプロキシのリストを表示させています。

「class=”A”>」と「</a></li>」のあいだの太字が、プロキシです。

 

正規表現で抽出

プロキシがどこに書いてあるか分かったら、今度はそれを抽出します。

コードでは、

Regex r = new Regex(@”class=””.””>(\d.*?)</a></li>“, RegexOptions.IgnoreCase | RegexOptions.Singleline);

で、入力された文字列のどこを抽出するか決めています。

 

class=””.””>(\d.*?)</a></li>

が正規表現です。

 

HTMLを見た結果、

「class=”A”>」もしくは「class=”B”>」

「</a></li>」

のあいだにプロキシがあると分かっています。

 

正規表現の

class=””.””>(\d.*?)</a></li>

は、それとマッチするようになっています。

 

以下、部分ごとに説明します。

 

class=””.””>

「class=”A”>」のような文字列とマッチする部分を探します。

 

「.」はなんでも、1文字という意味。

Aのところは、何か1文字入っていればマッチします。

「class=”B”>」もあるため

 

(\d.*?)

括弧の中の正規表現にマッチした部分を、実際に抽出(切り出し)しています。

 

括弧内の「\d.*?」は、何か数字から始まる文字列。

という意味。

 

  • 「\d」は半角数字
  • 「.」は任意の一文字
  • 「*?」は直前文字の0回以上の繰り返し

 

「51.68.92.17:8080」のような、プロキシそのものが一致。

抽出されます。

 

</a></li>

この部分は固定された表現。

 

一致する部分を探しており、ここまでを1セットとしています。

これが検出されるとまた次の、「class=”A”>」のような文字列を探します。

 

正規表現部分の意味

まとめると、

class=””.””>(\d.*?)</a></li>

の意味は、

class=”A”>」や「class=”B”>」と「</a></li>」の間の、数字から始まる文字列を抽出。

です。

 

プロキシリストを抽出

正規表現で、プロキシリストを抽出するコード。

「抽出する」部分以外も含めた全体は、このようになります。

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net; //追加してください。
using System.IO; //追加してください。
using System.Text.RegularExpressions; //追加してください。(正規表現を利用するため)

namespace getProxy
{
    class Program
    {
        static void Main(string[] args)
        {
            string proxySite = "http://www.cybersyndrome.net/pla5.html"; //プロキシリストのあるサイトURL
            string source = ""; //プロキシリストをふくむウェブソースを入れるハコ

            if (getSource(proxySite, ref source)) //サイトソースをダウンロードする
            {
                //ダウンロード成功したときの処理
                Console.WriteLine("ソースのダウンロードに成功しました...URL:" + proxySite);

                //ダウンロードしたソースを(念のため)記録しておく
                StreamWriter st = new StreamWriter("source.txt", false); //ソースを書き込むファイルを開く
                st.Write(source); //ダウンロードしたソースを書き込む
                st.Close(); //ファイルを閉じる

                //ソースからプロキシを取り出す
                List<string> proxies = extractProxy(source);

                //プロキシをファイルに書き込む
                StreamWriter st2 = new StreamWriter("proxies.txt", false); //プロキシを書き込むファイルを開く
                foreach (string proxy in proxies)
                {
                    st2.Write(proxy + "\n"); //プロキシを書き込む
                }
                st2.Close(); //ファイルを閉じる
                Console.ReadKey(); //キー入力待ち
            }
            else
            {
                //ダウンロード失敗したときの処理
                Console.WriteLine("ダウンロードに失敗しました。");
                Console.ReadKey(); //キー入力待ち
            }
        }
        static List<string> extractProxy(string source)
        {
            //プロキシをいれるためのリスト
            List<string> proxies = new List<string>();

            //取り出したい文字列を正規表現で書く
            Regex r = new Regex(@"class=""."">(\d.*?)</a></li>", RegexOptions.IgnoreCase | RegexOptions.Singleline);

            //書いた正規表現とソースを比較。一致した文字列をリストに入れる。
            MatchCollection mc = r.Matches(source);

            //正規表現のための特殊なリスト型から普通の文字列リストへコピー
            foreach (Match m in mc) proxies.Add(m.Groups[1].Value);

            return proxies;
        }
        static bool getSource(string url, ref string source)
        {
            HttpWebRequest webreq = (HttpWebRequest)
            WebRequest.Create(url);
            try
            {
                //ウェブサイトの内容をダウンロード
                HttpWebResponse webres = (HttpWebResponse)webreq.GetResponse();
                Stream st = webres.GetResponseStream();

                //ウェブサイトの内容をハコにいれる
                StreamReader sr = new StreamReader(st);
                source = sr.ReadToEnd();

                st.Close();
                sr.Close();
            }
            catch (WebException e)
            {
                Console.WriteLine(e.Message); //ダウンロードに失敗した場合、理由を表示
                Console.WriteLine("getSourceで例外が発生しました。\n" + url);
                return false;
            }
            return true;
        }
    }
}

 

  1. getSourceメソッドでHTMLをダウンロード
  2. extractProxyメソッドでプロキシを抽出

しています。

 

正規表現を使うため、

using System.Text.RegularExpressions;

は、コードの最初に必ず必要です。

 

この記事には、コード領域でない平文にもコードがあります。そういう箇所では、本来半角ダブルクオーテーションのところも全角となっています。

 

タイトルとURLをコピーしました