【C#】正規表現でプロキシリストを取り出す

C#

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

C#でプロキシリストのあるサイトにアクセスし、プロキシをダウンロードするコードです。

今回はダウンロードしたソースコードから正規表現でプロキシを取り出します。

しかし、処理の流れや正規表現の作りかたはプロキシ以外のときも同じです。

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;
        }
    }
}

getSource(string url, ref string source)

まずは、プロキシリストがあるサイトのソースをダウンロードします。

 

List<string> extractProxy(string source)の使いかた

取ってきたソースからプロキシを取り出し、リストへ書き込みます。

引数

先ほどダウンロードしたソースを入れます。

返り値

プロキシのリストが入ってきます。

using

正規表現を使うため、

using System.Text.RegularExpressions;

をコードの最初に書き加えてください。

List<string> extractProxy(string source)の解説

メソッドの意味と、どういう考えで作ったか、書いていきます。

ソースを読んでみる

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

<a title=”AF” onMouseOver=”s(‘AF’,’121-100-49-1.rdns.afghan-wireless.com’)” onMouseOut=”d()” class=”A”>121.100.49.1:80</a></li>・・・・・・・

といった表現が連続しているところがあります。

ここが、サイト上でプロキシを順番に表示させているところです。

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

正規表現で取り出す

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

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

のところで、ソースの中のどんな文字列を取り出すか、決めています。

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

のところが正規表現と言われるものです。

先ほどのソースコードで、

「class=”A”>」と「</a></li>」のあいだにプロキシがあると分かっています。

この正規表現はそれと一致するようになっています。

 

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

"class=""."">

「class=”A”>」のような文字列と一致する。

ただし、Aのところは何か1文字入っていれば一致とする。

という意味です。

「class=”B”>」とか「class=”C”>」という表記もたくさんあるためです。

(\d.*?)

()は、()内を”一致した文字列リスト”に入れる。

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

という意味です。

 

まとめると、

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

は、

「class=”A”>」みたいなものと「</a></li>」のあいだの、数字から始まる文字列を取ってくる。

という意味になります。

注意点

この記事には、コード領域でない平文にコードが書いてあるところがあります。

そういう箇所では、本来半角ダブルクオーテーションのところも全角となっています。

ご注意ください。

更新履歴

2017/07/02:半角ダブルクオーテーションを全角に差し替え。