2011-08-16 3 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.

나는 몸을 잡아하는 방법에 대한 준비가 예를 가지고 있지 않지만, 난 단지 링크를 잡아하는 방법 중 하나가 않고 약간의 수정과가 얻을 것이다. 여기에 거친 버전입니다 : 당신은 M12 파서를 열 필요가

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

(예제 프로젝트 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 : 니스. 나는 Majest 12에 관해 몰랐다. 나는 그것을 조사해야 할 것이다. –

+0

@Lirik : 나도 확인하고 싶다. 당신이 더 어렵다고 말하면, 그것이 얼마나 다른지를 지적 해 주시겠습니까? 온라인 설명서 나 샘플을 볼 수 없습니다. – 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

간단한/가장 빠른 (가장 정확한) 방법을. 분명히 HEAD 태그와 같은에서 자바 스크립트가 있다면

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

...
document.write("<body>"); 

그런 다음 당신은 당신이 원하는 그 다음 조금 더 될 겁니다.

+0

+1은 빠른 작업을 위해 간단하고 빠른 답변을 추가합니다. 모두가 프레임 워크를 다운로드하고 배포하려는 것은 아니며, 특히 한 번만 사용하기를 원합니다. 이것이 왜 downvoted되었는지 잘 모르겠습니다. . . –

관련 문제