我怎么能只刮“身体”呢?网站的标签

本文关键字:网站 标签 身体 怎么能 | 更新日期: 2023-09-27 18:05:40

我正在做一个网络爬虫。此时我刮掉整个内容,然后使用正则表达式删除<meta>, <script>, <style>和其他标签,并获得正文的内容。

然而,我试图优化性能,我想知道是否有一种方法,我可以刮只有页面的<body> ?

namespace WebScraper
{
    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;
        }
    }
}

Page_Load我调用scrapeIt()方法传递给它的字符串,我从一个文本框从页面。

我怎么能只刮“身体”呢?网站的标签

仍然是最简单/最快(最不准确)的方法。

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>");

我建议利用HTML Agility Pack来做HTML解析/操作。

您可以像这样轻松地选择正文:

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

我认为你最好的选择是使用轻量级的HTML解析器(像Majestic 12这样的东西,根据我的测试,它比HTML Agility Pack快大约50-100%),并且只处理你感兴趣的节点(<body></body>之间的任何节点)。Majestic 12比HTML Agility Pack更难使用,但如果你想提高性能,那么它肯定会对你有所帮助!

这将为您提供您所要求的关闭,但您仍然需要下载整个页面。我认为没有别的办法。您保存的内容实际上是为所有其他内容(除了正文)生成DOM节点。您必须对它们进行解析,但是您可以跳过对处理不感兴趣的节点的整个内容。

下面是如何使用M12解析器的一个很好的示例。

我没有一个现成的如何抓取主体的例子,但我确实有一个如何只抓取链接的例子,并且经过很少的修改,它将到达那里。这里是粗略的版本:

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

您需要打开M12解析器(M12附带的示例项目有详细说明所有这些选项如何影响性能的注释,并且它们确实如此!!):

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

解析正文:

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节点很棘手,但是majessitic12toxml类将帮助您完成这一工作。就像我说的,这绝不等同于你在HTML敏捷包中看到的3-liner,但是一旦你掌握了这些工具,你将能够以一小部分的性能成本和可能同样多的代码行获得你所需要的东西。