SGMLReaderがことごとくタイムアウトする件
例えば,
neue cc - C#でスクレイピング:HTMLパース(Linq to Html)のためのSGMLReader利用法からお借りしたこんなコード.
static void Main(string[] args) { XDocument xml; using (var sgml = new SgmlReader() { Href = "http://www.bing.com/search?cc=jp&q=linq" }) { xml = XDocument.Load(sgml); } XNamespace ns = "http://www.w3.org/1999/xhtml"; foreach (var item in xml.Descendants(ns + "h3")) { Console.WriteLine(item.Value); } }
やってることはWebページを取得してそれをXDocumentに突っ込んでるだけなんですが,xml = XDocument.Load(sgml);
のところで必ずタイムアウトでWebExceptionが投げられる.
神が助けて下さいました
泣きついたとも言います.
@HIDARI0415 @shinsukeoda 確かに例外出ますね。調べてみましたが、いつのバージョンからかわからないですがご丁寧にdtd読みに行くようになってますね。IgnoreDtd = trueというのを足せば読みに行かなくなるので動きました!
— neuecc (@neuecc) 2014, 3月 26
つまりデフォルトでは必ずDTD(HTMLタグの前に記述される<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
とかいうやつ)が宣言されてる必要があるということ.
指定が無いデータをSGMLReaderに渡すと今回のように例外が投げられます.
んで,これを無視するように IgnoreDtd = true
って設定することでDTD宣言の無いHTMLでも扱えるようになる,と.
以下,修正した部分のサンプル.
using (var sgml = new SgmlReader() { Href = "http://www.bing.com/search?cc=jp&q=linq" }) { sgml.IgnoreDtd = true; // これが無いと例外で死ぬ xml = XDocument.Load(sgml); }
出力は
LinQ | 九州発のアイドルグループ
リンク - Wikipedia
www.loveinq.com
LINQ: .NET 統合言語クエリ
LinQオフィシャルブログ - Ameba (アメーバ)|無料ブログ ...
LINQ (C# によるプログラミング入門)
LinQ|Warner Music Japan
LinQ・LinK|テレ朝動画 - tv asahi|テレビ朝日
LinQ|HMV ONLINE
LinQ|ニュース|Warner Music Japan - ワーナーミュージック ...
となりました.
おわりに
@HIDARI0415 @shinsukeoda PCL版はDTDまわりバサッとカットされてますね。
— neuecc (@neuecc) 2014, 3月 26
PCL版のSGMLReaderではDTD周りの処理がカットされているということなので,こちらを使えばこの問題は起こらn(ry
@neue先生,@shinsukeoda先生ありがとうございました!