HTML5 を多用するサイトでの互換性

1. 背景―なぜ HTML5 が課題になるか

HtmlAgilityPack(以下 HAP)は HTML 4.01/XHTML 体系の DTD を前提にしたストリーミング‐トークン型パーサ を核にしています。
一方 HTML5 仕様は “タグ閉じ忘れの許容”“名前空間混在(SVG・MathML)”“新しい暗黙的終了規則” など独自のパース・ツリー生成アルゴリズムを採用しており、DTD 非依存 である点が決定的に異なります。
そのため HTML5 要素を多用するサイト をそのまま HAP に読み込むと、以下のような不整合・情報欠落が起こり得ます。


2. 主な制限事項と典型的な影響

分類 制限ポイント 具体的な影響例
新要素の扱い <section> / <article> / <nav> / <header> / <footer> などに特別な意味づけ無し 暗黙的終了規則が働かず 意図しない入れ子構造になる場合がある
コンポーネント系 <template>・Web Components(カスタム要素) <template> 内部は “ただのテキスト” として解析され、DOM が生成されない
メディア関連 <picture><source srcset="..."> <source>自己閉じ と判定されず、後続のノードが <picture> 内へ誤って吸収される
名前空間要素 SVG・MathML 名前空間属性が脱落し、<svg> 直下の子要素がフラットに並ぶ
属性仕様 srcset, autocomplete, novalidate 等の HTML5 boolean/複数値属性 未知属性として読み込むため文字列取得は出来るが 論理属性 としての真偽判定がアプリ側で必要
追加実体参照 &Cross;, &sup1; など HTML5 Named Character References HtmlEntity.DeEntitize() が未定義のため生文字列に戻らず実体参照のまま残る

3. 代表的な不具合シナリオ

  1. ブログ記事 DOM の断裂
    <article> に続いてすぐ <section> が開き <section> を閉じ忘れたまま次の <article> が登場すると、HAP は階層を強制修正しないため記事ごとの切れ目が判別不能になる。

  2. 画像ギャラリーの srcset 消失
    レスポンシブ画像を抽出したいのに、<source> 要素が正しく閉じられず兄弟要素が子要素化し、srcset 属性も取得漏れとなるケース。

  3. SVG アイコンが空要素化
    <svg><path d="..."/></svg>path明示的閉じタグ を持たないと “空テキストノード” だけが残り、パスデータが欠落。


4. 回避策・緩和策

アプローチ 内容 適用指針
AngleSharp との二段階パース csharp<br>var doc = await BrowsingContext.New(Configuration.Default).OpenAsync(req => req.Content(html));<br>var hap = new HtmlDocument();<br>hap.LoadHtml(doc.ToHtml()); HTML5 準拠パーサで一度 “正規 DOM” を作ってから HAP へ橋渡し。タグ補完・名前空間保持・既知エンティティ展開が確実
PuppeteerSharp / Playwright での事前レンダリング JS で生成・変換されるノード(Web Components など)をヘッドレスブラウザ側で innerHTML として取得してから解析 画面描画後の “最終 DOM” が欲しいスクレイピングで有効
HTML Tidy / HtmlSanitizer による XHTML 変換 tidy -asxhtml 相当で明示閉じタグと名前空間宣言を補完 オフライン処理で大量文書を一括変換する場合に高速
HAP オプション強化 csharp<br>var doc=new HtmlDocument{<br>OptionFixNestedTags=true,<br>OptionOutputAsXml=true,<br>OptionWriteEmptyNodes=true}; 軽度なタグ閉じ忘れや孤立テキストノードの修正なら十分
エンティティ拡張テーブル HtmlEntity.AddEntity("#x2715", "×"); など自前登録 ニッチな新規 Named Entity が必要で AngleSharp を併用しないケース

5. 実装ベストプラクティス

  1. “どこまで HAP に任せるか” を最初に決める

    • 静的 HTML → HAP 単独 でも OptionFixNestedTags + 正規表現フォローで済む場合多い

    • 動的生成 or Web Components → AngleSharp / ブラウザ自動化 を前提にしたワークフローへ移行

  2. 検証用ユニットテストを必ず用意
    HTML5 ページ断片を 最小ケース に分解し、Assert.Equal() でノード階層を比較する。これにより暗黙閉じ規則のズレを早期発見できる。

  3. 名前空間要素は “除外 or 別ライブラリ” で扱う
    SVG 解析が目的なら SvgDocument/Svg.Skia など専門パーサへ分業し、HAP では OuterHtml ごと除去してしまう。

  4. 長期的には AngleSharp への乗り換えを検討
    HAP はメンテナンスコストが低く軽量ですが、HTML5 仕様全体への追随度は限定的です。HTML5 固有要素・属性を主体とするモダンサイトのクローリングが中心業務なら AngleSharp + CSS Selectors & LINQ をメインとし、HAP は XHTML エクスポート/XPath 処理特化ツール として残す構成が保守的にも安全です。


まとめ

HtmlAgilityPack は HTML5 を多用するサイト に対しては 構文修復の限界未知要素の扱い により整合性問題が発生します。
しかし AngleSharp 併用・ヘッドレスブラウザ前処理・XHTML への正規化 などを組み合わせれば、大半のケースで実用上支障のない DOM ツリーを得ることが可能です。
目的に応じて 「軽量・高速」 vs 「HTML5 完全準拠」 のトレードオフを見極め、適切なパーサ選定と前処理フローを設計してください。

ChatGPT4o 生成日:2025/06/23