• 强大而灵活的的Html解析器——Html Agility Pack


    一、概述

    Html Agility Pack 简称HAP,是一个强大而灵活的解析Html DOM的.Net类库。

    二、官方链接

    官网:http://html-agility-pack.net/

    NuGet: https://www.nuget.org/packages/HtmlAgilityPack/

    Github:https://github.com/zzzprojects/html-agility-pack

    三、用法及示例

    1、解析前需要加载资源,有四种方式载入:

    (1) File

    var path = @"D:test.html";
            
    var doc = new HtmlDocument();
    doc.Load(path);

    以上的path是自己的文件路径,这样html被加载到了Doc之后就可以解析了。

    (2) String

    var html = @"<!DOCTYPE html>
    <html>
    <body>
    	<h1>This is <b>bold</b> heading</h1>
    	<p>This is <u>underlined</u> paragraph</p>
    	<h2>This is <i>italic</i> heading</h2>
    </body>
    </html> ";
    
    var htmlDoc = new HtmlDocument();
    htmlDoc.LoadHtml(html);
    
    var htmlBody = htmlDoc.DocumentNode.SelectSingleNode("//body");
    

     以上的html是一个html格式的字符串。通过LoadHtml加载到了htmlDoc。在爬虫过程中通过url获取的html内容字符串后,就可以通过这种方式加载。

    (3) Web

    var html = @"http://html-agility-pack.net/";
    
    HtmlWeb web = new HtmlWeb();
    
    var htmlDoc = web.Load(html);

    这个方法则是直接通过url加载。如果是只有url,则较之前一种方法更为简单,不需要再另写通过url获取html内容字符串的方法。

    (4) Browser

    string url = "http://html-agility-pack/from-browser";
    
    var web1 = new HtmlWeb();
    var doc1 = web1.LoadFromBrowser(url, o =>
    {
        var webBrowser = (WebBrowser) o;
    
        // WAIT until the dynamic text is set
        return !string.IsNullOrEmpty(webBrowser.Document.GetElementById("uiDynamicText").InnerText);
    });
    var t1 = doc1.DocumentNode.SelectSingleNode("//div[@id='uiDynamicText']").InnerText;
    
    var web2 = new HtmlWeb();
    var doc2 = web2.LoadFromBrowser(url, html =>
    {
        // WAIT until the dynamic text is set
        return !html.Contains("<div id="uiDynamicText"></div>");
    });
    var t2 = doc2.DocumentNode.SelectSingleNode("//div[@id='uiDynamicText']").InnerText;
    
    Console.WriteLine("Text 1: " + t1);
    Console.WriteLine("Text 2: " + t2);

    此方法需要在WinForm中使用。通过LoadFromBrowser方法来加载.

    2、选择器

    (1) SelectNodes(),选择与xPath表达式匹配的节点,如果不存在匹配的节点,则返回null.

    示例1:返回匹配表达式“/td/input”的节点集合


    var
    htmlDoc = new HtmlDocument(); htmlDoc.LoadHtml(html);
    string name = htmlDoc.DocumentNode
    .SelectNodes("//td/input");

    当需要只返回匹配的第一个节点时,用.first。

    string name = htmlDoc.DocumentNode
        .SelectNodes("//td/input")
        .First()

    用first的前提是这种节点要存在。否则返回的是null时不能再用first。因此可以先获取匹配的节点集合,判断不为空的情况下,再用first:

    var inputNodes = htmlDoc.DocumentNode.SelectNodes("//td/input");
    if (inputNodes!=null)
    {
      string name = inputNodes.First();
    }

    示例2:通过class或者id等返回匹配节点,以下是为了获取class='news-item'的所有div节点。

    var mainNode = htmlDoc.DocumentNode.SelectNodes(@"//div[@class='news-item']");

    当然,div可以根据需要换成span、h1、img等节点。class也可以根据需要换成id或其他。

    (2) SelectSingleNode 。获取第一个匹配Xpath表达式的节点。节点不存在则返回null。

    示例1:

    var htmlDoc = new HtmlDocument();
    htmlDoc.LoadHtml(html);
    
    string name = htmlDoc.DocumentNode
        .SelectSingleNode("//td/input");

    示例2:

    var firstNode = htmlDoc.DocumentNode.SelectSingleNode(@"//div[@class='viewport']");

     (3)结合linq的使用更强大: 通过where方法或者firstordefault方法,以及节点的特性或者节点的内容等获取节点。

    示例:

    HtmlWeb web = new HtmlWeb();
                var doc = web.Load(model.Url);
                var textNode = doc.DocumentNode.Descendants("div").FirstOrDefault(m => m.GetAttributeValue("class", "") == "text" && m.GetAttributeValue("dir", "") == "ltr");

    var tdNode = htmlDoc.DocumentNode.SelectNodes(@"//td[@colspan='3']").Where(n => n.InnerHtml.Contains("<a href=") && n.InnerHtml.Contains("<p align=")).FirstOrDefault();
    3、通过以上方式获取节点后,就可以对节点进行操作了。

    InnerHtml:获取或设置节点内的html。

    var htmlDoc = new HtmlDocument();
    htmlDoc.LoadHtml(html);
    
    var htmlNodes = htmlDoc.DocumentNode.SelectNodes("//body/h1");
    
    foreach (var node in htmlNodes)
    {
        Console.WriteLine(node.InnerHtml);
    }

    InnerText:获取或设置节点内的text。

    var htmlDoc = new HtmlDocument();
    htmlDoc.LoadHtml(html);
    
    var htmlNodes = htmlDoc.DocumentNode.SelectNodes("//body/h1");
    
    foreach (var node in htmlNodes)
    {
        Console.WriteLine(node.InnerText);
    }

    AppendChild:向指定节点的末尾增加子节点:

    var htmlDoc = new HtmlDocument();
    htmlDoc.LoadHtml(html);
    
    var htmlBody = htmlDoc.DocumentNode.SelectSingleNode("//body");
            
    HtmlNode h2Node = HtmlNode.CreateNode("<h2> This is h2 heading</h2>");
    
    htmlBody.AppendChild(h2Node);

    Remove:移除节点

    var htmlDoc = new HtmlDocument();
    
    htmlDoc.LoadHtml(html);
    
    var htmlBody = htmlDoc.DocumentNode.SelectSingleNode("//body");
    
    HtmlNode node = htmlBody.ChildNodes[1];
    
    node.Remove();
    遍历

    ChildNodes:获取所有子节点:

    var htmlDoc = new HtmlDocument();
    htmlDoc.LoadHtml(html);
    
    var htmlBody = htmlDoc.DocumentNode.SelectSingleNode("//body");
            
    HtmlNodeCollection childNodes = htmlBody.ChildNodes;
            
    foreach (var node in childNodes)
    {
        if (node.NodeType == HtmlNodeType.Element)
        {
            Console.WriteLine(node.OuterHtml);
        }
    }    

    FirstChild:获取第一个子节点:

    var htmlDoc = new HtmlDocument();
    htmlDoc.LoadHtml(html);
    
    var htmlNodes = htmlDoc.DocumentNode.SelectNodes("//body");
    
    var htmlBody = htmlDoc.DocumentNode.SelectSingleNode("//body");
            
    HtmlNode firstChild = htmlBody.FirstChild;
            
    Console.WriteLine(firstChild.OuterHtml);    

    LastChild:获取最后一个子节点,示例同上。

    Descendants():返回所有后代节点:

    var node = htmlDoc.DocumentNode.SelectSingleNode("//body");
    
    foreach (var nNode in node.Descendants())
    {
        if (nNode.NodeType == HtmlNodeType.Element)
        {
            Console.WriteLine(nNode.Name);
        }
    }

    Descendants(String):获取指定名称的后代节点:

    var node = htmlDoc.DocumentNode.SelectSingleNode("//body");
    
    foreach (var nNode in node.Descendants("h2"))
    {
        if (nNode.NodeType == HtmlNodeType.Element)
        {
            Console.WriteLine(nNode.Name);
        }
    }
    属性

    SetAttributeVaule设置节点属性:

    var h1Node = htmlDoc.DocumentNode.SelectSingleNode("//h1");
            
    h1Node.Attributes.Append("style");
            
    h1Node.SetAttributeValue("style", "color:blue");

    GetAttributeVaule获取节点属性:

    如下例子中常用来在爬虫中获取音视频的url

    var source = htmlDoc.DocumentNode.SelectSingleNode(@"//source[@type='audio/mpeg']");
    var audioUrl = source.GetAttributeValue("src", "");

    如下示例常用来在爬虫中获取title

    var title = childHtmlDoc.DocumentNode.SelectSingleNode(@"//input[@name='title']").GetAttributeValue("value", "");
  • 相关阅读:
    Linux系统目录结构介绍
    【Android开发学习笔记】【第二课】Activity学习
    【Android开发学习笔记】【第一课】初识New Project,工程文件介绍
    Android 环境快速搭建-详细步骤-win7-64bit
    【VC6】【集成工具】将输入信息集成到VC工具中
    Intellij IDEA快捷键
    C#+Winform开发窗体程序
    使用U盘重装系统
    C#进阶学习笔记
    C#基础学习笔记
  • 原文地址:https://www.cnblogs.com/dayang12525/p/7976422.html
Copyright © 2020-2023  润新知