2011-08-16 9 views
7

Sto lavorando a un webcrawler. Al momento scrivo l'intero contenuto e poi usando l'espressione regolare rimuovo <meta>, <script>, <style> e altri tag e ottengo il contenuto del corpo.Come raschiare solo il tag <body> da un sito Web

Tuttavia, sto cercando di ottimizzare le prestazioni e mi chiedevo se c'era un modo per raschiare solo lo <body> della pagina?

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; 
     } 
    } 
} 

Da Page_Load chiamo il metodo scrapeIt() passandogli la stringa che mi da una casella di testo dalla pagina.

+2

Certo, ma abbiamo bisogno di vedere il tuo attuale codice di scraping –

risposta

3

Penso che l'opzione migliore sia utilizzare un parser HTML leggero (something like Majestic 12, che in base ai miei test è circa il 50-100% più veloce di HTML Agility Pack) e elaborare solo i nodi a cui sei interessato (qualsiasi cosa tra <body> e </body>). Majestic 12 è un po 'più difficile da usare rispetto a HTML Agility Pack, ma se stai cercando prestazioni allora ti sarà sicuramente d'aiuto!

Questo ti porterà a chiudere ciò che stai chiedendo, ma dovrai comunque scaricare l'intera pagina. Non penso che ci sia un modo per aggirare questo. Quello che si salva su sta effettivamente generando i nodi DOM per tutti gli altri contenuti (oltre al corpo). Dovrai analizzarli, ma puoi saltare l'intero contenuto di un nodo che non ti interessa elaborare.

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

io non avere un esempio di come pronta ad afferrare il corpo, ma io ho uno di come afferrare solo i collegamenti e con poca modifica essa sarà arrivarci. Ecco la versione grezza:

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

è necessario aprire la M12 Parser (il progetto di esempio che viene fornito con M12 ha commenti che dettagli esattamente come tutte queste opzioni influenzano le prestazioni, e lo fanno !!!):

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; 
} 

Analizzare il corpo:

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; 
     }; 
    } 
} 

Generare i nodi DOM è difficile, ma il Majestic12ToXml class will help you do that. Come ho detto, questo non è affatto equivalenti al 3-liner che avete visto con il pacchetto agilità HTML, ma una volta che gli strumenti sono stati scaricati, sarai in grado di ottenere esattamente ciò di cui hai bisogno per una frazione del costo delle prestazioni e probabilmente altrettante linee di codice.

+0

+1: Bello. Non sapevo di Majest 12. Dovrò verificarlo. –

+0

@Lirik: Vorrei verificarlo anche io; dici che è più difficile, puoi indicare qualcosa di diverso? Non riesco a vedere alcuna documentazione o campioni online. – casperOne

+0

Grazie Lirik. L'unica cosa è che non riesco a trovare la documentazione o l'API per usare questa libreria. Potresti indicarmi un link? – Johancho

5

Suggerire di sfruttare lo HTML Agility Pack per eseguire l'analisi/manipolazione HTML.

È possibile selezionare facilmente il corpo in questo modo: il metodo

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

Hey Joel, grazie per aver dedicato del tempo per aiutarti. Come mi può essere d'aiuto HtmlAgilityPack? Non devo prima caricare la pagina e poi analizzare la stringa? – Johancho

+0

Il pacchetto agility può caricare e analizzare la pagina. Ho aggiornato il mio esempio. Analizzare te stesso può essere un grande dolore, specialmente se non è perfettamente formato. Il pacchetto di agilità è davvero buono. –

+0

Il pacchetto agility dovrà caricare e analizzare la pagina in anticipo, aggiungendo ulteriore sovraccarico. Sebbene sia una soluzione semplice e accurata, NON è veloce o efficiente. –

4

Ancora più semplice/veloce (meno preciso).

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

Ovviamente se c'è javascript nel tag HEAD come ...

document.write("<body>"); 

Poi si ritroverà con un po 'di più allora si voleva.

+0

+1 per aggiungere una risposta semplice e veloce per un lavoro veloce. Non tutti vogliono scaricare e distribuire framework, soprattutto per un uso singolo. Non so perché questo è stato downvoted. . . –

Problemi correlati