HTML Parser "dcsoup" を公開しました。
Javaで書かれたHTML Parser、“jsoup” を .NET (C#) に移植中です。なんとなく動く感じなのでとりあえず公開しました。
https://github.com/matarillo/dcsoup
これは何?
HTMLパーサーです。こんな感じで使います。
using System; using System.Globalization; using System.Net.Http; using Supremes; class Program { public static void Main(string[] args) { // 株価を取得したいサイトのURL var code = "7984.T"; var urlstring = string.Format("http://stocks.finance.yahoo.co.jp/stocks/detail/?code={0}", code); using (var client = new HttpClient()) { // 指定したサイトのHTMLを取得する var message = client.GetAsync(urlstring).Result; // dcsoupでパースする var document = message.Parse(); // jQueryライクなセレクタで株価部分を取得する var priceNode = document.Select("td[class=stoksPrice]")[0]; // 取得した株価がstring型なのでint型にパースする var price = int.Parse(priceNode.Text, NumberStyles.AllowThousands); Console.WriteLine("コクヨ(7984.T)の株価: {0}円", price); } } }
あ、何やってるかが分かりにくいですね。using Supremes;
でSystem.Net.Http.HttpResponseMessage
クラスに対してParse()
拡張メソッドが有効になってます。
文字列、ファイル、ストリームなどからパースするときは Supremes.Dcsoup
静的クラスを使うとよいです。
HTML Agility Packと何が違うの?
「jQueryライクなセレクタ」のとこが、XPathよりもっとjQueryライクです。
using System; using System.Net.Http; using Supremes; class Program { public static void Main(string[] args) { using (var client = new HttpClient()) { var doc = client.GetAsync("http://ja.wikipedia.org/").Result.Parse(); var featuredArticles = doc.Select("#mf-tfa b a"); Console.WriteLine(featuredArticles.Text); } } }
パーサーはHTMLの構造を知っています。たとえば次のようなHTMLをパースすると……
using System; using Supremes; class Program { public static void Main(string[] args) { var doc = Dcsoup.Parse("<table> <tr> <td>ABC <td>DEF <td>GHI </tr></table>"); Console.WriteLine(doc); } }
出力はこうなります。
<html> <head></head> <body> <table> <tbody> <tr> <td>ABC </td> <td>DEF </td> <td>GHI </td> </tr> </tbody> </table> </body> </html>
さらに、jQueryライクにパース結果のDOMを変更できます。上のコードに1行追加してみましょう。
using System; using Supremes; class Program { public static void Main(string[] args) { var doc = Dcsoup.Parse("<table> <tr> <td>ABC <td>DEF <td>GHI </tr></table>"); doc.Select("td").AddClass("foo bar"); // クラスを追加 Console.WriteLine(doc); } }
その結果、出力はこうなりました。
<html> <head></head> <body> <table> <tbody> <tr> <td class=" foo bar">ABC </td> <td class=" foo bar">DEF </td> <td class=" foo bar">GHI </td> </tr> </tbody> </table> </body> </html>
既知の問題
テストコードがまだコンバートされていません。テストコードをコンバート中です。テストのコンバートが終わってバグ修正もしました。テストに通ります。元のjsoupにはないバグが多く含まれています。すぐ例外を吐いて死にます。目立つバグは潰したので、わりとちゃんと動くと思います。ただし、元のjsoupとはAPIレベルでの差異や、細かい挙動の違いはあります。いずれGitHubにまとめます。ライブラリに含まれるクラスのプロパティが、Javaっぽい部分と、jQueryっぽい部分と、.NETっぽい部分がぐちゃぐちゃになってます。いずれきちんとした指針を立てた上で整理したいのですが。.NETのプロパティに基本的に寄せました。あとで記事を書きます。まだNuGetで配布してません。テストがまともに通るようになったら考えます。テストに通るようになったので着手します。できました。