2009-05-25 12 views
8

HTML文書を解析していくつかの要素(テキストファイルへのリンク)を抽出しようとしています。HTMLドキュメントの解析:正規表現またはLINQ?

現在の戦略は、HTMLドキュメントを文字列にロードすることです。次に、テキストファイルへのリンクのすべてのインスタンスを検索します。どんなファイルタイプでも構いませんが、この質問のためにテキストファイルです。

最後の目標は、IEnumerable文字列オブジェクトのリストを持つことです。その部分は簡単ですが、データの解析は問題です。

<html> 
<head><title>Blah</title> 
</head> 
<body> 
<br/> 
<div>Here is your first text file: <a href="http://myServer.com/blah.txt"></div> 
<span>Here is your second text file: <a href="http://myServer.com/blarg2.txt"></span> 
<div>Here is your third text file: <a href="http://myServer.com/bat.txt"></div> 
<div>Here is your fourth text file: <a href="http://myServer.com/somefile.txt"></div> 
<div>Thanks for visiting!</div> 
</body> 
</html> 

初期のアプローチは、以下のとおりです。

  • は、XMLドキュメントに文字列をロードし、LINQのからXML形式でそれを攻撃します。
  • href=から始まる文字列を探すために、正規表現を作成し、.txt

で質問ビーイング終了:その正規表現が好きなものを見える

  • を?私は正規表現初心者であり、これは私の正規表現学習の一部です。
  • どの方法を使用してタグのリストを抽出しますか?
  • これは最も効果的な方法でしょうか?
  • どのメソッドが最も読みやすく/維持可能でしょうか?


アップデート:HTML敏捷性パックの提案にMatthewから 賞賛。それはうまくいった! XPathの提案も同様に機能します。私は両方の答えを '答え'にすることができたらいいと思いますが、明らかにできません。どちらも問題の有効な解決策です。

ここには、Jeffで提案されている正規表現を使用したC#コンソールアプリがあります。それは文字列の細かい部分を読み込み、.txtで終わっていないhrefは含めません。与えられたサンプルでは、​​(HTML文字列関数で提供されているように)結果にファイル.txt.snargが正しく含まれません。

using System; 
using System.Collections.Generic; 
using System.Text; 
using System.Text.RegularExpressions; 
using System.IO; 

namespace ParsePageLinks 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      GetAllLinksFromStringByRegex(); 
     } 

     static List<string> GetAllLinksFromStringByRegex() 
     { 
      string myHtmlString = BuildHtmlString(); 
      string txtFileExp = "href=\"([^\\\"]*\\.txt)\""; 

      List<string> foundTextFiles = new List<string>(); 

      MatchCollection textFileLinkMatches = Regex.Matches(myHtmlString, txtFileExp, RegexOptions.IgnoreCase); 
      foreach (Match m in textFileLinkMatches) 
      { 
       foundTextFiles.Add(m.Groups[1].ToString()); // this is your captured group 
      } 

      return files; 
     } 

      static string BuildHtmlString() 
      { 
       return new StringReader(@"<html><head><title>Blah</title></head><body><br/> 
<div>Here is your first text file: <a href=""http://myServer.com/blah.txt""></div> 
<span>Here is your second text file: <a href=""http://myServer.com/blarg2.txt""></span> 
<div>Here is your third text file: <a href=""http://myServer.com/bat.txt.snarg""></div> 
<div>Here is your fourth text file: <a href=""http://myServer.com/somefile.txt""></div> 
<div>Thanks for visiting!</div></body></html>").ReadToEnd(); 
      }  
     } 
    } 
+0

オープンソースのHTMLパーサーを使用していますか? – Jeff

+0

@JD:絶対に!マシューが示唆したように、HTMLアジリティパックは一見の価値があります。あなたはそれを提案するつもりでしたか? –

+1

@Philoushka私はHTMLアジリティパックを提案しようとしていました...それは岩です。 – Jeff

答えて

1

:XPathを使用して

サンプル実装。どうして?

  • に簡単に柔軟な(ケース非感受性は、新しいファイル拡張子、 チェックする要素などを追加)

正規表現式を実行するために

  • 高速を書くことがファスト
  • は、限り、あなたは正規表現を書くことができるよう、読みにくいことはありません。

    href="([^"]*\.txt)"

    説明:

    • それは "キャプチャグループ" になります ファイル名を括弧で囲む、持っている正規表現としてこれを使用して

      各一致が見つかるたびに にアクセスできます。

    • "。"をエスケープする必要があります。正規表現エスケープ文字の を使用して、バックスラッシュを作成します。
    • それは 二重引用符以外の任意の文字にマッチしなければならない:[^ "]それは
      見つかるまで" .TXT」

    を、それがこのようなエスケープ文字列に変換します。

    string txtExp = "href=\"([^\\\"]*\\.txt)\" 
    

    次に、あなたの試合を反復処理することができます。また

    Matches txtMatches = Regex.Matches(input, exp, RegexOptions.IgnoreCase); 
    foreach(Match m in txtMatches) { 
        string filename = m.Groups[1]; // this is your captured group 
    } 
    
  • +1

    @Jeff:これは優れたコードサンプルです。入力いただきありがとうございます! –

    +4

    これは、OPが明示的に "ends with"と言ったときに、hrefのどこでも.txtにマッチします。私の意見では、正規表現はここでは不適切です。 –

    +0

    @Matthew:いいえ、(.txt ")で終わるHREFにのみ一致します.HREFの中に引用符が含まれているとは思わない –

    12

    どちらもありません。それを(X/HT)MLDocumentにロードし、XPathを使用します。これはXMLを操作する標準的な方法であり、非常に強力です。見る機能はSelectNodesSelectSingleNodeです。

    明らかにHTML(XHTMLではなく)を使用しているため、HTML Agility Packを使用する必要があります。ほとんどのメソッドとプロパティは、関連するXMLクラスと一致します。私は正規表現をお勧めします

    HtmlDocument doc = new HtmlDocument(); 
        doc.Load(new StringReader(@"<html> 
    <head><title>Blah</title> 
    </head> 
    <body> 
    <br/> 
    <div>Here is your first text file: <a href=""http://myServer.com/blah.txt""></div> 
    <span>Here is your second text file: <a href=""http://myServer.com/blarg2.txt""></span> 
    <div>Here is your third text file: <a href=""http://myServer.com/bat.txt""></div> 
    <div>Here is your fourth text file: <a href=""http://myServer.com/somefile.txt""></div> 
    <div>Thanks for visiting!</div> 
    </body> 
    </html>")); 
         HtmlNode root = doc.DocumentNode; 
         // 3 = ".txt".Length - 1. See http://stackoverflow.com/questions/402211/how-to-use-xpath-function-in-a-xpathexpression-instance-programatically 
         HtmlNodeCollection links = root.SelectNodes("//a[@href['.txt' = substring(., string-length(.)- 3)]]"); 
        IList<string> fileStrings; 
        if(links != null) 
        { 
         fileStrings = new List<string>(links.Count); 
         foreach(HtmlNode link in links) 
         fileStrings.Add(link.GetAttributeValue("href", null)); 
        } 
        else 
         fileStrings = new List<string>(0); 
    
    +2

    @Matthew:HTML Agility Packは、約5分で実現したものです。サンプルとソースが付属しています。サイモン・ミュリエへの名誉! –

    +0

    Agilityパックの "LINQ to HTML"のサポートもあります。 –

    0

    をマシューFlaschenの提案に、DOM (例: ?スマートヘルパー)が実装は時々面白いです、そしてネイティブCOMインターフェイスは、いくつかの(マイナーなしビット扱いにくいので、私は推測するが、 - あなたはXからLアレルギーの発生)

    を被る場合、それは時々悪評を取得します私はHTMLを解析して操作するために、堅牢で安定した、直感的な/探索可能な方法を見つけました。

    +2

    実際に彼はCOM interop経由で.NETのIEのHTMLパーサーを使用することを提案しています...。 –

    +0

    ああ待って、彼は "C#"と言った....その場合、noooo。 – peterchen

    0

    REGEXは高速ではありません。実際、.NETのネイティブ文字列解析の処理よりも処理速度が遅いです。私を信じてはいけません、あなた自身のために見てください。

    上記の例はどれも、DOMに直接行くよりも高速です。

    HTMLDocument doc = wb.Document; 
    var links = doc.Links; 
    
    関連する問題