2011-08-16 12 views
7

私はウェブクローラーで作業しています。瞬間、私はコンテンツ全体を掻き集めて正規表現を使って<meta>, <script>, <style>と他のタグを取り除き、本文の内容を取得します。<body>タグのみをウェブサイトから削り取るには

しかし、私はパフォーマンスを最適化しようとしていますが、ページの<body>だけを掻き取る方法があるのでしょうか? Page_Loadから

namespace WebScrapper 
{ 
    public static class KrioScraper 
    {  
     public static string scrapeIt(string siteToScrape) 
     { 
      string HTML = getHTML(siteToScrape); 
      string text = stripCode(HTML); 
      return text; 
     } 

     public static string getHTML(string siteToScrape) 
     { 
      string response = ""; 
      HttpWebResponse objResponse; 
      HttpWebRequest objRequest = 
       (HttpWebRequest) WebRequest.Create(siteToScrape); 
      objRequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; " + 
       "Windows NT 5.1; .NET CLR 1.0.3705)"; 
      objResponse = (HttpWebResponse) objRequest.GetResponse(); 
      using (StreamReader sr = 
       new StreamReader(objResponse.GetResponseStream())) 
      { 
       response = sr.ReadToEnd(); 
       sr.Close(); 
      } 
      return response; 
     } 

     public static string stripCode(string the_html) 
     { 
      // Remove google analytics code and other JS 
      the_html = Regex.Replace(the_html, "<script.*?</script>", "", 
       RegexOptions.Singleline | RegexOptions.IgnoreCase); 
      // Remove inline stylesheets 
      the_html = Regex.Replace(the_html, "<style.*?</style>", "", 
       RegexOptions.Singleline | RegexOptions.IgnoreCase); 
      // Remove HTML tags 
      the_html = Regex.Replace(the_html, "</?[a-z][a-z0-9]*[^<>]*>", ""); 
      // Remove HTML comments 
      the_html = Regex.Replace(the_html, "<!--(.|\\s)*?-->", ""); 
      // Remove Doctype 
      the_html = Regex.Replace(the_html, "<!(.|\\s)*?>", ""); 
      // Remove excessive whitespace 
      the_html = Regex.Replace(the_html, "[\t\r\n]", " "); 

      return the_html; 
     } 
    } 
} 

は、私はそれに私がページからテキストボックスから取得した文字列を渡すscrapeIt()メソッドを呼び出します。

+2

確かに、現在のスクレイピングコードを参照する必要があります –

答えて

3

あなたの最善の選択肢は、軽量のHTMLパーサー(something like Majestic 12、私のテストによるとHTMLアジリティパックより約50-100%速い)を使用し、興味のあるノードだけを処理することです<body></body>の間)。 Majestic 12はHTML Agility Packよりも使用するのが少し難しいですが、パフォーマンスを探しているなら間違いなくあなたを助けます!

これはあなたに求めていることを締めくくるでしょうが、それでもページ全体をダウンロードする必要があります。その周りに道があるとは思わない。あなたがになるとは実際には他のすべてのコンテンツのDOMノードを生成しています(本体以外)。それらを解析する必要がありますが、処理に興味のないノードのコンテンツ全体をスキップすることができます。

Here is a good example of how to use the M12 parser.

は私が身体をつかむ方法の準備の例を持っていないが、私は唯一のリンクをつかむ方法のいずれかを持っていますし、少しの変更で、それはそこに着くでしょう。ここでは大まかなバージョンは次のとおりです。

GrabBody(ParserTools.OpenM12Parser(_response.BodyBytes)); 

あなたはM12パーサを開く必要があります(M12に付属しているサンプルプロジェクトの詳細が正確にどのようにこれらのオプションのすべてがパフォーマンスに影響を与えるという意見を持っている、と彼らはDO !!!):

私が言ったように、これはあなたが見た3・ライナーと同等でないことは、 Majestic12ToXml class will help you do that.

public void GrabBody(HTMLparser parser) 
{ 

    // parser will return us tokens called HTMLchunk -- warning DO NOT destroy it until end of parsing 
    // because HTMLparser re-uses this object 
    HTMLchunk chunk = null; 

    // we parse until returned oChunk is null indicating we reached end of parsing 
    while ((chunk = parser.ParseNext()) != null) 
    { 
     switch (chunk.oType) 
     { 
      // matched open tag, ie <a href=""> 
      case HTMLchunkType.OpenTag: 
       if (chunk.sTag == "body") 
       { 
        // Start generating the DOM node (as shown in the previous example link) 
       } 
       break; 

      // matched close tag, ie </a> 
      case HTMLchunkType.CloseTag: 
       break; 

      // matched normal text 
      case HTMLchunkType.Text: 
       break; 

      // matched HTML comment, that's stuff between <!-- and --> 
      case HTMLchunkType.Comment: 
       break; 
     }; 
    } 
} 

DOMノードを生成することは難しいですが、:

public static HTMLparser OpenM12Parser(byte[] buffer) 
{ 
    HTMLparser parser = new HTMLparser(); 
    parser.SetChunkHashMode(false); 
    parser.bKeepRawHTML = false; 
    parser.bDecodeEntities = true; 
    parser.bDecodeMiniEntities = true; 

    if (!parser.bDecodeEntities && parser.bDecodeMiniEntities) 
     parser.InitMiniEntities(); 

    parser.bAutoExtractBetweenTagsOnly = true; 
    parser.bAutoKeepScripts = true; 
    parser.bAutoMarkClosedTagsWithParamsAsOpen = true; 
    parser.CleanUp(); 
    parser.Init(buffer); 
    return parser; 
} 

体を解析HTMLアジリティパックを使用していますが、いったんツールを入手すると、パフォーマンスコストのほんのわずかで、おそらく数多くのコードラインで、必要なものを正確に得ることができます。

+0

+1:ニース。私はMajest12については知らなかった。私はそれを調べなければならないだろう。 –

+0

@リリック:私もそれをチェックしたいと思います。あなたはそれがもっと難しいと言います、あなたはそれがどのように違うかについて何かを指摘できますか?私はオンラインのドキュメントやサンプルを見ることができません。 – casperOne

+0

ありがとうLirik。唯一のことは、このライブラリを使用するためのドキュメントやAPIが見つかりません。私にリンクを教えてもらえますか? – Johancho

5

私は、HTML Agility Packを利用してHTMLの解析/操作を行うことをお勧めします。

あなたは簡単にこのように体を選択することができます。まだ

var webGet = new HtmlWeb(); 
var document = webGet.Load(url); 
document.DocumentNode.SelectSingleNode("//body") 
+0

ヘイジョエル、お手伝いをしてくれてありがとう。 HtmlAgilityPackはどのように私に役立つでしょうか?最初にページをロードしてから文字列を解析する必要はありませんか? – Johancho

+0

アジリティパックはページを読み込んで解析することができます。私は私の例を更新しました。 htmlを自分で解析することは、特に完全に形成されていない場合、大きな痛みになる可能性があります。アジリティパックは本当に上手いです。 –

+0

アジリティパックは手を加える前にページを読み込んで解析する必要があり、余分なオーバーヘッドが加わります。シンプルで正確なソリューションですが、高速で効率的ではありません。 –

4

最も簡単/最速(少なくとも正確な)方法。明らかに

int start = response.IndexOf("<body", StringComparison.CurrentCultureIgnoreCase); 
int end = response.LastIndexOf("</body>", StringComparison.CurrentCultureIgnoreCase); 
return response.Substring(start, end-start + "</body>".Length); 

HEADタグ内のJavaScriptが

document.write("<body>"); 

が...のようにありますならば、あなたは、あなたが望んでいたその後、もう少しで終わるでしょう。

+0

クイックジョブのためのシンプルで速い回答を追加するための+1。誰もがフレームワークをダウンロードして配備することを望んでいるわけではありません。なぜこれが下落したのか分かりません。 。 。 –

関連する問題