zoukankan      html  css  js  c++  java
  • c#解析HTML

    当我们需要解析一个web页面的时候,如果非常简单,可以用字符串查找的方式,复杂一点可以用正则表达式,但是有时候正则很麻烦的,因为html代码本身就比较麻烦,像常用的img标签,这个东东到了浏览器上就没了闭合标签(一直还没搞懂为什么),想用XML解析,也是同样的原因根本解析不了,今天发现一个解析html控件,用了一下,非常好用。

    这个控件叫做Html Agility Pack,主页在这儿:http://htmlagilitypack.codeplex.com/

    这儿还有一篇blog介绍怎么使用的 (English):http://olussier.net/2010/03/30/easily-parse-html-documents-in-csharp/

    我直接把例子贴这儿,一看就明白。因为是作为xml解析的,所以呢,少不了XPath,如果不懂这个东西的话,赶紧看看吧,现在xpath语法都扩展到css里面了,语法比较简单,先看看基础的就行了。

    最基本的使用方法不是SelectSingleNode,而是GetElementById,这是与XmlDocument不同的地方。

    // The HtmlWeb class is a utility class to get the HTML over HTTP
    HtmlWeb htmlWeb = new HtmlWeb();
      
    // Creates an HtmlDocument object from an URL
    HtmlAgilityPack.HtmlDocument document = htmlWeb.Load("http://www.somewebsite.com");
      
    // Targets a specific node
    HtmlNode someNode = document.GetElementbyId("mynode");
      
    // If there is no node with that Id, someNode will be null
    if (someNode != null)
    {
      // Extracts all links within that node
      IEnumerable<htmlnode> allLinks = someNode.Descendants("a");
      
      // Outputs the href for external links
      foreach (HtmlNode link in allLinks)
      {
        // Checks whether the link contains an HREF attribute
        if (link.Attributes.Contains("href"))
        {
          // Simple check: if the href begins with "http://", prints it out
          if (link.Attributes["href"].Value.StartsWith("http://"))
            Console.WriteLine(link.Attributes["href"].Value);
        }
      }
    }</htmlnode>

    使用xpath

    // Extracts all links under a specific node that have an href that begins with "http://"
    HtmlNodeCollection allLinks = document.DocumentNode.SelectNodes("//*[@id='mynode']//a[starts-with(@href,'http://')]");
      
    // Outputs the href for external links
    foreach (HtmlNode link in allLinks)
        Console.WriteLine(link.Attributes["href"].Value);

    One more

    path = "//table[@id='1' or @id='2' or @id='3']//a[@onmousedown]"; 
    xpath = "//ul[@id='wg0']//li[position()<4]/h3/a"; 
    xpath = "//div[@class='resitem' and position()<4]/a";
    xpath = "//li[@class='result' and position()<4]/a";

     使用方法:

    刚刚学习了XPath路径表达式,主要是对XML文档中的节点进行搜索,通过XPath表达式可以对XML文档中的节点位置进行快速定位和访问,html也是也是一种类似于xml的标记语言,但是语法没有那么严谨,在codeplex里有一个开源项目HtmlAgilityPack提供了用XPath解析HTML文件,下面掩饰如何使用该类库的使用

    首先说下XPath路径表达式

    XPath路径表达式

      用来选取XML文档中的节点或节点集的

      1、术语:节点(Node):7种类型:元素,属性,文本,命名空间,处理命令,注释,文档(根)节点

      2、节点关系:父(Parent),子(Children),同胞(Sibling),先辈(Ancestor),后代(Descendant)

      3、路径表达式

       nodename  节点名,选取此节点的所有子节点  例: childnode  当前节点中的childnode子节点,不包含孙子及以下的节点

          /     从根节点选取  例:/root/childnode/grandsonnode  

           //     表示所有后代节点  例://childnode    所有名为childnode的后代节点

          .    表示当前节点  例:  ./childnode    表示当前节点的childnode节点

          ..     表示父节点  例:  ../nearnode     表示父亲节点的nearnode子节点

           @    选取属性  /root/childnode/@id     表示childnode的所有含有id属性的节点集

      4、谓语(Predicates)

        谓语可以对节点集进行一些限制,使选择更精确

          /root/book[1]    节点集中的第一个节点

          /root/book[last()]  节点集中最后一个节点

          /root/book[position() - 1]  节点集中倒数第二个节点集

          /root/book[position() < 5]  节点集中前五个节点集

          /root/book[@id]      节点集中含有属性id的节点集

          /root/book[@id='chinese']  节点集中id属性值为chinese的节点集

          /root/book[price > 35]/title  节点集中book的price元素值大于35的title节点集

      5、通配符:XPath路径中同样支持通配符(*,@*,node(), text())

        例:  /bookstore/*

            //title[@*]

      6、XPath轴

        定义相对于当前节点的节点集

          ancestor    所有祖先节点

          attribute    所有属性节点

          child      所有子元素

          descendant  所有后代节点(子,孙。。。)

          following    结束标记后的所有节点      preceding   开始标记前的所有节点

          following-sibling  结束标记后的所有同胞节点

          preceding-sibling  开始标记前的所有同胞节点

          namespace   当前命名空间的所有节点

          parent     父节点

          self       当前节点

        用法:轴名称::节点测试[谓语]

          例:  ancestor::book

                child::text()

      7、运算符

        |  两个节点集的合并  例:/root/book[1] | /root/book[3]

        +,-,*,dev,mod

        =,!=,<,>,<=,>=

        or,and  或和与

    //删除注释,script,style
        node.Descendants()
                    .Where(n => n.Name == "script" || n.Name == "style" || n.Name=="#comment")
                    .ToList().ForEach(n => n.Remove());
    
    
        //遍历node节点的所有后代节点
        foreach(var HtmlNode in node.Descendants())
        {
            
        }

    HtmlAgilityPack类库用法

      1、首先需要获取到html页面数据,可以通过WebRequest类来获取

    public static string GetHtmlStr(string url)
            {    
                try
                {
                    WebRequest rGet = WebRequest.Create(url);
                    WebResponse rSet = rGet.GetResponse();
                    Stream s = rSet.GetResponseStream();
                    StreamReader reader = new StreamReader(s, Encoding.UTF8);
                    return reader.ReadToEnd();
                }
                catch (WebException)
                {
                    //连接失败
                    return null;
                }
            }

     2、通过HtmlDocument类加载html数据

            string htmlstr = GetHtmlStr("http://www.hao123.com");
            HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
            doc.LoadHtml(htmlstr);
            HtmlNode rootnode = doc.DocumentNode;    //XPath路径表达式,这里表示选取所有span节点中的font最后一个子节点,其中span节点的class属性值为num
            //根据网页的内容设置XPath路径表达式
            string xpathstring = "//span[@class='num']/font[last()]";    
            HtmlNodeCollection aa = rootnode.SelectNodes(xpathstring);    //所有找到的节点都是一个集合
            
            if(aa != null)
            {
                string innertext = aa[0].InnerText;
                string color = aa[0].GetAttributeValue("color", "");    //获取color属性,第二个参数为默认值
                //其他属性大家自己尝试
            }

    也可以通过HtmlWeb类来获得HtmlDocument

      HtmlWeb web = new HtmlWeb();
            HtmlAgilityPack.HtmlDocument doc = web.Load(url);
            HtmlNode rootnode = doc.DocumentNode;

    补充:

      多个属性条件查询      //div[@align='center' and @height='24']

      不存在class属性       //div[not(@class)]

  • 相关阅读:
    Java入门系列之集合Hashtable源码分析(十一)
    哈希算法原理【Java实现】(十)
    Java入门系列之集合LinkedList源码分析(九)
    双链表算法原理【Java实现】(八)
    Java入门系列之集合ArrayList源码分析(七)
    动态数组原理【Java实现】(六)
    Java入门系列之类继承、抽象类、接口(五)
    Java入门系列之包装类(四)
    Java入门系列之StringBuilder、StringBuffer(三)
    Java入门系列之字符串特性(二)
  • 原文地址:https://www.cnblogs.com/yubinfeng/p/3774751.html
Copyright © 2011-2022 走看看