あらかじめ日記

雑記とかブログで使えるスクリプトとかテクニックとか。その他、音楽やアニメ、漫画の話題とかも。

【C#】URLからタイトルを取得して<a>タグを作成する (改善版)

allthewayfrom.hatenablog.com

上記の記事からの続きです。


対象のURLを読み込むためにWebBrowserクラスが便利だったので使っていたのですが、ブラウザのレンダリング込みの読み込みのため、たかがタイトルを取得するためだけであまりレスポンスが良くない。

そこで少し改善をしてみました。

 
そもそも欲しいのはタイトルだけなので全部読み込む必要は無く、何か良い方法がないか見ていたところ、WebBrowserクラスにはReadyStateと言うプロパティで読み込みの状態を持っているので、これがLoaded以上まで来たら良さそうです。
そこで、DocumentCompletedではなく、ProgressChangedのイベントをハンドリングしてReadyStateを逐次チェック。Loaded以上ならStopさせて終わる、と言う方法で結構良くなりました。


…なのですが、DocumentTitleのプロパティで簡単にタイトルが取れることからWebBrowserクラスを使ったものの、それでもやはりタイトルだけなのでやっぱりWebClientで作り直します(結局)。

WebClientはリクエストしたURLがHTMLでそのまま来るので、解析が必要になります。
ただ、タイトルくらいなら正規表現で検索して取ってこれるため、大した話ではないのですが問題なのはエンコード
(これが最初に、WebClientを使わなかった理由でもあります)

通常はリクエスト結果に関連付けられているヘッダ内、もしくはmetaタグ内のcharsetを見て判別しますが、未設定だったり間違っていたりする可能性もあり結構厄介

IEが利用しているmlang.dllを利用する方法もありますが、C#で使うためにはこれがまた面倒そう。。

色々見ていたところ、自動判別するDLLを2014年版で公開されている方がいました!

d.hatena.ne.jp

これを使わせてもらえばもうcharsetの判別もいらないでしょう。ありがたく使用させて頂きます。

あっさり問題が解決したので、最初からこっちで作っておけば良かったと思いつつも改善完了です。

以下、サンプルです。

WebClient wclnt = new WebClient();

string htmlText = "";
using (Stream strm = wclnt.OpenRead("http://www.yahoo.co.jp/")) {
	byte[] byteData;
	byte[] buf = new byte[short.MaxValue];

	using (MemoryStream ms = new MemoryStream()) {

		while (true) {
			int read = strm.Read(buf, 0, buf.Length);

			if (read > 0) {
				ms.Write(buf, 0, read);
			}
			else {
				break;
			}
		}
		byteData = ms.ToArray();
	}
	// バイトデータから自動判別でエンコードした文字列を取得
	Hnx8.ReadJEnc.ReadJEnc.JP.GetEncoding(byteData, byteData.Length, out htmlText);
}
// 正規表現でtitleタグ内のテキストのみ取得
Match regmch = Regex.Match(htmlText, "(?.*?)", RegexOptions.IgnoreCase | RegexOptions.Singleline);
string title = regmch.Groups["title"].Value;


この流れで、サムネイル画像の取得とかも自動化できそうですね。
(それはまた次の機会にでも。。)