こんにちは、ひつじ先輩です。
C#で正規表現を使い、文字列から任意のパターンを抽出します。
とくに、スクレイピングをやりたい人には役立つはずです。
- サイトのソースコードを取得
- 文字列から欲しい部分を抽出
がスクレイピングの流れ。
この記事では、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; }
- 文字列が入力される
- 正規表現でマッチした部分を抽出
- 当てはまる文字列をリストで返す
をやっています。
具体的には、プロキシのリストをふくむ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>
といった表現が連続していたとします。
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文字入っていればマッチします。
(\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; } } }
- getSourceメソッドでHTMLをダウンロード
- extractProxyメソッドでプロキシを抽出
しています。
正規表現を使うため、
using System.Text.RegularExpressions;
は、コードの最初に必ず必要です。