HIDARI日記(右)

そのときどき興味ある技術を中心にだらだら書いてます。内容は個人の見解であり、所属する企業を代表するものではありません。

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が投げられる.

神が助けて下さいました

泣きついたとも言います.

つまりデフォルトでは必ず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 - ワーナーミュージック ...

となりました.

おわりに

PCL版のSGMLReaderではDTD周りの処理がカットされているということなので,こちらを使えばこの問題は起こらn(ry

@neue先生,@shinsukeoda先生ありがとうございました!