正規表現でHTML(XML)から指定のデータを取得したい
C#/VB.NETでHTMLから指定タグの値や属性を取得するには正規表現が使えます。LINQ to XMLでもHTML(XML)から要素や属性の操作が可能ですが、不正なXMLドキュメントの場合にはうまく使えません。
Webページをスクレイピングする場合などは、必ずしも正しいHTMLとは限りません。閉じタグが抜けていたり、Javascriptなどが埋め込まれていたらうまくいきません。
LINQ to XMLではXMLへの書き込みや保存を行えるのも大きな特徴ですが、データの取得だけであれば正規表現で十分です。
指定のタグから値と属性を取得する
例えば次のようなHTMLがあったとき、リンク内容をすべて取得し列挙します。処理的には a タグからリンクのテキストとURLを取得しています。
reg.html
<!DOCTYPE html>
<html>
<head>
<title>正規表現でリンクを取得します</title>
</head>
<body>
<a href="http://link1.com">リンク1</a>
<p>
あいうえお<a href="http://link2.net">
リンク2
</a>
</p>
<a href='http://link3.org'>
リンク3
</a>
<a class="link" href='http://link4.jp'>リンク4</a>
</body>
</html>
C#
//using System.Text.RegularExpressions;
// aタグにマッチする正規表現
var reg = @"<a\s+[^>]*href\s*=\s*[""'](?<href>[^""']*)[""'][^>]*>(?<text>[^<]*)</a>";
using (var reader = new StreamReader(@"reg.html"))
{
var text = reader.ReadToEnd();
var r = new Regex(reg, RegexOptions.IgnoreCase);
var collection = r.Matches(text);
foreach (Match m in collection)
{
// マッチした情報を出力
Console.WriteLine($"{m.Groups["text"].Value.Trim()}:{m.Groups["href"]}");
}
}
VB.NET
' aタグにマッチする正規表現
Dim reg As String = "<a\\s+[^>]*href\\s*=\\s*[""'](?<href>[^""']*)[""'][^>]*>(?<text>[^<]*)</a>"
Using reader = New StreamReader("reg.html")
Dim text As String = reader.ReadToEnd
Dim r As Regex = New Regex(reg, RegexOptions.IgnoreCase)
Dim collection = r.Matches(text)
For Each m As Match In collection
' マッチした情報を出力
Console.WriteLine($"{m.Groups("text").Value.Trim()}:{m.Groups("href")}")
Next
End Using
正規表現の意味
正規表現でHTMLから情報を抽出する場合、どこまでマッチさせるかで難易度が変わってきます。こちらでも同じことをしていますが、上のサンプルは違う表現を使っています。
aタグのhref属性の値を、(?<href>[^""']*)で取得しています。クォート、ダブルクォート以外からなる文字列をhrefという名前を付けてマッチさせています。
テキストの値は、(?<text>[^<]*)で取得しています。<a ..> ~ </a>の閉じタグ部分の”<"にマッチするまでの文字列をテキスト部分としてマッチさせています。aタグ内にさらにタグが入れ子になっている場合は想定していません。
タグ内での改行や余計な属性、スペースにも対応しているはずです。上記HTML内のaタグのURLとテキストはすべて取得できています。
まとめ
上記サンプルを参考にすれば、ある程度柔軟にHTMLからデータを取得できるはずです。
参考URL
コメントを書く