zoukankan      html  css  js  c++  java
  • some things

    ////html[1]/body[1]/div[9]/div[1]/div[1]/div[1]/ul/li  截取规则
    Articles/Article[1]:选取属于Articles子元素的第一个Article元素。 

    /Articles/Article[last()]:选取属于Articles子元素的最后一个Article元素。 
    /Articles/Article[last()-1]:选取属于Articles子元素的倒数第二个Article元素。 
    /Articles/Article[position()<3]:选取最前面的两个属于 bookstore 元素的子元素的Article元素。 
    //title[@lang]:选取所有拥有名为lang的属性的title元素。 
    //CreateAt[@type='zh-cn']:选取所有CreateAt元素,且这些元素拥有值为zh-cn的type属性。 
    /Articles/Article[Order>2]:选取Articles元素的所有Article元素,且其中的Order元素的值须大于2。 
    /Articles/Article[Order<3]/Title:选取Articles元素中的Article元素的所有Title元素,且其中的Order元素的值须小于3。

    刚刚学习了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    所有祖先节点

    //删除注释,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())
        {
            
        }

          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  或和与

    补充:

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

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

    static void Main(string[] args)
            {
                //<ul class="user_match clear">
                //    <li>年龄:21~30之间</li>
                //    <li>婚史:未婚</li>
                //    <li>地区:不限</li>
                //    <li>身高:175~185厘米之间</li>
                //    <li>学历:不限</li>
                //    <li>职业:不限</li>
                //    <li>月薪:不限</li>
                //    <li>住房:不限</li>
                //    <li>购车:不限</li>
                //</ul>
    
    
                WebClient wc = new WebClient();
                wc.BaseAddress = "http://www.juedui100.com/";
                wc.Encoding = Encoding.UTF8;
                HtmlDocument doc = new HtmlDocument();
                string html = wc.DownloadString("user/6971070.html");
                doc.LoadHtml(html);
                HtmlNode node = doc.DocumentNode.SelectSingleNode("/html/body/div[4]/div[1]/div[2]/ul[1]");     //根据XPath查找节点,跟XmlNode差不多
    
                IEnumerable<HtmlNode> nodeList = node.Ancestors();  //获取该元素所有的父节点的集合
                foreach (HtmlNode item in nodeList)
                {
                    Console.Write(item.Name + " ");   //输出 div div body html #document
                }
                Console.WriteLine();
    
                IEnumerable<HtmlNode> nodeList1 = node.Ancestors("body");  //获取名字匹配的该元素的父集合,其实参数就是一个筛选的功能
                foreach (HtmlNode item in nodeList1)
                {
                    Console.Write(item.Name + " ");   //输出 body
                }
                Console.WriteLine();
    
                IEnumerable<HtmlNode> nodeList2 = node.AncestorsAndSelf();  //获取所有的父节点和自身
                foreach (HtmlNode item in nodeList2)
                {
                    Console.Write(item.Name + " "); //输出 ul div div div body html #document
                }
                Console.WriteLine();
    
                IEnumerable<HtmlNode> nodeList3 = node.AncestorsAndSelf("div");     //获取父节点和自身,参数用于筛选
                foreach (HtmlNode item in nodeList3)
                {
                    Console.Write(item.Name + " "); //输出 div div div
                }
                Console.WriteLine();
    
                HtmlNode node1 = doc.CreateElement("li");
                node1.InnerHtml = "我是附加的li元素";
                node.AppendChild(node1);    //...<li>购车:不限</li> 后面加了一个<li>我是附加的li元素</li>
                Console.WriteLine(node.InnerHtml);
    
    
                HtmlNode node2 = doc.CreateElement("li");
                node2.InnerHtml = "新li一";
                HtmlNode node3 = doc.CreateElement("li");
                node3.InnerHtml = "新li二";
                HtmlNodeCollection nc = new HtmlNodeCollection(node2);
                nc.Add(node2);
                nc.Add(node3);
                node.AppendChildren(nc);    //一次过追加多个元素
                Console.WriteLine(node.InnerHtml);      //...<li>我是附加的li元素</li><li>新li一</li><li>新li二</li>
    
                Console.WriteLine(HtmlNode.CanOverlapElement("node2"));     //输出False   确定是否可以保存一个重复的元素
    
                IEnumerable<HtmlAttribute> attrs = node.ChildAttributes("class");   //获取子节点与自身的所有名为class的属性集合
                foreach (HtmlAttribute attr in attrs)
                {
                    Console.Write(attr.Value);      //输出 user_match clear 
                }
    
                HtmlNode node4 = node.Clone();
                Console.WriteLine(node4.InnerHtml);     //输出node的代码,node已被复制到了node
    
                HtmlNode node5 = node.CloneNode(false); //参数决定是否复制子节点,与XmlNode一样
                Console.WriteLine(node5.OuterHtml);     //<ul class="user_match clear"></ul>    因为参数设为了false子节点没有被复制
    
                HtmlNode node6 = node.CloneNode("div");    //复制节点的同时,更改名字
                Console.WriteLine(node6.OuterHtml);        //输出 <div class="user_match clear"><li>年龄:21~30之间</li>...</div>  ul已被改为了div
    
                HtmlNode node7 = node.CloneNode("table",false);
                Console.WriteLine(node7.OuterHtml);        //输出<table class="user_match clear"></table>     参数为false所以没有复制子节点
    
                HtmlNode node8 = node.SelectSingleNode("child::li[1]");
                node.CopyFrom(node);
                Console.WriteLine(node.OuterHtml);
                Console.WriteLine("========================");
                //public void CopyFrom(HtmlNode node);
                //public void CopyFrom(HtmlNode node, bool deep);
                //public XPathNavigator CreateNavigator();
                //public XPathNavigator CreateRootNavigator();
    
                HtmlNode node9 = HtmlNode.CreateNode("<li>新节点</li>");   //直接用字符串创建节点,还是挺好用的
                Console.WriteLine(node9.OuterHtml);     //输出 <li>新节点</li>
    
                IEnumerable<HtmlNode> nodeList4 = node.DescendantNodes();   //获取所有的子节点集合
                foreach (HtmlNode item in nodeList4)
                {
                    Console.Write(item.OuterHtml);      //输出 node的每个子li节点
                }
                Console.WriteLine("===================");
    
                IEnumerable<HtmlNode> nodeList5 = node.DescendantNodesAndSelf();
                foreach (HtmlNode item in nodeList5)
                {
                    Console.Write(item.OuterHtml);      //输出自身<ul>..包括子节点<li>...</li></ul> 再输出所有的子li节点
                }
                Console.WriteLine();
    
                IEnumerable<HtmlNode> nodeList6 = node.DescendantNodes();   //获取枚举列表中的所有子代节
                foreach (HtmlNode item in nodeList6)
                {
                    Console.Write(item.InnerText);  //输出所有的li节点的内容
                }
                Console.WriteLine("---------------");
    
                IEnumerable<HtmlNode> nodeList7 = node.Descendants("li");   //获取所有的子后代元素    //文本节点不在此范围内
                foreach(HtmlNode item in nodeList7)
                {
                    Console.Write(item.InnerText);   
                }
    
                IEnumerable<HtmlNode> nodeList8 = node.DescendantsAndSelf("ul");   //获取所有的子后代元素    //文本节点不在此范围内
                foreach (HtmlNode item in nodeList8)
                {
                    Console.Write(item.Name);       //输出 ul 参数实际上只相当于过滤的作用
                }
    
                HtmlNode node10 = node.Element("li");   //获取第一个子节点名称匹配的元素
                Console.WriteLine(node10.InnerText);        //输出 年龄:年龄:21~30之间
                Console.WriteLine("----------------------------------------");
    
                IEnumerable<HtmlNode> nodeList9 = node.Elements("li");
                foreach (HtmlNode item in nodeList9)
                {
                    Console.Write(item.InnerText);      //输出 所有的li节点内容
                }
                Console.WriteLine();
    
                //换一个新的,好像有点乱了
                HtmlNode newnode = doc.DocumentNode.SelectSingleNode("/html/body/div[4]/div[1]/div[3]");
                //<div class="col say">
                //    <h3>爱情独白</h3>
                //    <p>愿得一心人,白首不相离。我一直相信我的另一半就在茫茫人海中,有一天一定会与我相遇。</p>
                //</div>
    
                //bool b = newnode.GetAttributeValue("class", false);   //获取一个布尔值的属性,没有找到则返回第二个参数的默认值
                //Console.WriteLine(b);
                //int i = newnode.GetAttributeValue("class", 0);        //获取一个整形的属性,没有找到则返回第二个参数的默认值
                //Console.WriteLine(i);
    
                string str = newnode.GetAttributeValue("class", "");    //获取一个字符串属性
                Console.WriteLine(str); //输出 col say
    
                HtmlNode node11 = HtmlNode.CreateNode("<b>我是加粗节点</b>");
                HtmlNode node12 = newnode.SelectSingleNode("h3");
                newnode.InsertAfter(node11, node12);    //意思是在node12代表的h3节点后面插入node11节点
                Console.WriteLine(newnode.InnerHtml);   //h3>爱情独白</h3><b>我是加粗节点</b><p>愿得一心人...      留意到b节点已经被插入到h3后面
    
                newnode.InsertBefore(node11, node12);   //再插入多一次,方法不同罢了,这次是在node12带包的h3前面插入
                Console.WriteLine(newnode.InnerHtml);   //<b>我是加粗节点</b><h3>爱情独白</h3><b>我是加粗节点</b><p>愿得一心人
    
                Console.WriteLine("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
                newnode.RemoveChild(node11);    //移除了第一个<b>我是加粗节点</b>   此方法的重载,第二个参数决定是否移除孙子节点
                Console.WriteLine(newnode.InnerHtml);   //<h3>爱情独白</h3><b>我是加粗节点</b><p>愿得一心人....
    
                newnode.RemoveAllChildren();        //移除所有子节点
                Console.WriteLine(newnode.OuterHtml);   //<div class="col say"></div>   所有子节点都被移除了
    
                newnode.RemoveAll();                    //移除所有的属性和子节点,由于子节点已经被上个方法移除了,因此这次连属性也移除了
                Console.WriteLine(newnode.OuterHtml);   //输出 <div></div>    注意到属性也被移除了。
    
                //都移除光了,再来一个,还是刚才那个
                HtmlNode newnode1 = doc.DocumentNode.SelectSingleNode("/html/body/div[4]/div[1]/div[3]");
                Console.WriteLine("===================");
                Console.WriteLine(newnode1.OuterHtml);  //输出 <div></div>    注意 移除是从HtmlDocument中移除的,再次获取获取不到了
    
                HtmlNode newnode2 = doc.DocumentNode.SelectSingleNode("/html/body/div[4]/div[1]/div[2]/div[2]/p");
                Console.WriteLine(newnode2.OuterHtml);
                //<p class="no_tip">她还没有设置不能忍受清单 
                //    <a href="javascript:invite(5971070,8,'邀请设置不能忍受');" class="link_b needlogin">邀请她设置</a>
                //</p>
                newnode2.Remove();    //从文档树中移除newnode2节点
                HtmlNode newnode3 = doc.DocumentNode.SelectSingleNode("/html/body/div[4]/div[1]/div[2]/div[2]/p");   //再次获取该节点
                //Console.WriteLine(newnode3.OuterHtml);  //报未将对象引用到对象的实例异常,明显是找不到了,
    
                HtmlNode newnode4 = doc.DocumentNode.SelectSingleNode("/html/body/div[4]/div[1]/div[1]/div/div[1]/p[2]/b[1]");
                Console.WriteLine(newnode4.OuterHtml);
                //<b>相册:
                //    <a href="/photo/6971070.html" class="red">4</a>张
                //</b>
                HtmlNode node17 = HtmlNode.CreateNode("<div>再次创建一个节点</div>");
                newnode4.PrependChild(node17);      //跟AppengChild类似,只是插入位置不同PrependChildren接受一个节点集合,一次过插入多个节点而已
                Console.WriteLine(newnode4.OuterHtml);  
                //输出
                //<b>相册:
                //    <div>再次创建一个节点</div>
                //    <a href="/photo/6971070.html" class="red">4</a>张
                //</b>
                HtmlNode node16 = newnode4.SelectSingleNode("child::a[1]");
                HtmlNode node18 = HtmlNode.CreateNode("<p>新建一行</p>");
                newnode4.ReplaceChild(node18, node16);
                Console.WriteLine(newnode4.OuterHtml);
                //输出
                //<b>相册:
                //    <div>再次创建一个节点</div>
                //    <p>新建一行</p>张      //留意到node16代表得节点已经被替换掉了
                //</b>
    
                HtmlNode node19 = newnode4.SelectSingleNode("child::p[1]");
                node19.SetAttributeValue("class","class1");
                Console.WriteLine(node19.OuterHtml);    //输出 <p class="class1">新建一行</p>
    
                Console.WriteLine(HtmlNode.IsOverlappedClosingElement("<a>我爱你</a>"));   //输出 False
                Console.WriteLine(HtmlNode.IsCDataElement("<a>我爱你</a>"));   //输出 False
                Console.WriteLine(HtmlNode.IsClosedElement("<a>我爱你</a>"));   //输出 False
                Console.WriteLine(HtmlNode.IsEmptyElement("<a>我爱你</a>"));   //输出 False
                Console.WriteLine(newnode4.OuterHtml);
    
    
                HtmlNode node20 = HtmlNode.CreateNode("<p>新的第二行</p>");
                newnode4.AppendChild(node20);
                HtmlNodeCollection hnc = newnode4.SelectNodes("//p");   //根据XPath一次过获取多个Node
                Console.WriteLine(hnc.Count);   //输出29
    
                string str1 = node20.WriteContentTo();
                Console.WriteLine(str1);    //输出 新的第二行  将节点内容写入字符串
    
                //public void WriteContentTo(TextWriter outText);
                //public string WriteTo();
                //public void WriteTo(TextWriter outText);
                //public void WriteTo(XmlWriter writer);
                Console.ReadKey();
            }

    var divs = html.CssSelect("div");  //all div elements

    var nodes = html.CssSelect("div.content"); //all div elements with css class ‘content’

    var nodes = html.CssSelect("div.widget.monthlist"); //all div elements with the both css class

    var nodes = html.CssSelect("#postPaging"); //all HTML elements with the id postPaging

    var nodes = html.CssSelect("div#postPaging.testClass"); // all HTML elements with the id postPaging and css class testClass 

    var nodes = html.CssSelect("div.content > p.para"); //p elements who are direct children of div elements with css class ‘content’ 

    var nodes = html.CssSelect("input[type=text].login"); // textbox with css class login 

    We can also select ancestors of elements:

    var nodes = html.CssSelect("p.para").CssSelectAncestors("div.content > div.widget");

     

    常用函数

    xpath的常用函数主要包含节点集函数,字符串函数,布尔函数,数字函数,网上的资料较多,在此就不再累述,可参考以下资料:

    [a] XPath, XQuery, and XSLT Functions http://www.w3schools.com/xpath/xpath_functions.asp

    [b] XPath Functions http://www.caucho.com/resin-3.0/xml/xpath-fun.xtp

    [c] XPath Functions(MSDN) http://msdn2.microsoft.com/en-us/library/ms256138.aspx

    常用定位语句实例

    1. //NODE[not(@class)] 所有节点名为node,且不包含class属性的节点

    2. //NODE[@class and @id] 所有节点名为node,且同时包含class属性和id属性的节点

    3. //NODE[contains(text(),substring] 所有节点名为node,且其文本中包含substring的节点

    //A[contains(text(),"下一页")] 所有包含“下一页”字符串的超链接节点

    //A[contains(@title,"文章标题")] 所有其title属性中包含“文章标题”字符串的超链接节点

    4. //NODE[@id="myid"]/text() 节点名为node,且属性id为myid的节点的所有直接text子节点

    5. BOOK[author/degree] 所有包含author节点同时该author节点至少含有一个的degree孩子节点的book节点

    6. AUTHOR[.="Matthew Bob"] 所有值为“Matthew Bob”的author节点

    7. //*[count(BBB)=2] 所有包含两个BBB孩子节点的节点

    8. //*[count(*)=2] 所有包含两个孩子节点的节点

    9. //*[name()='BBB'] 所有名字为BBB的节点,等同于//BBB

    10. //*[starts-with(name(),'B')] 所有名字开头为字母B的节点

    11. //*[contains(name(),'C')] 所有名字中包含字母C的节点

    12. //*[string-length(name()) = 3] 名字长度为3个字母的节点

    13. //CCC | //BBB 所有CCC节点或BBB节点

    14. /child::AAA 等价于/AAA

    15. //CCC/descendant::* 所有以CCC为其祖先的节点

    16. //DDD/parent::* DDD节点的所有父节点

    17. //BBB[position() mod 2 = 0] 偶数位置的BBB节点

    18. AUTHOR[not(last-name = "Bob")] 所有不包含元素last-name的值为Bob的节点

    19. P/text()[2] 当前上下文节点中的P节点的第二个文本节点

    20. ancestor::BOOK[1] 离当前上下文节点最近的book祖先节点

    21. //A[text()="next"] 锚文本内容等于next的A节点

     

     

    最后推荐一款在Firefox中用的XPath插件:

    XPath Checker

    https://addons.mozilla.org/en-US/firefox/addon/1095

    这个插件可以方便查看网页中任意元素的XPath路径,但其自动生成的XPath路径通常不是最简路径。

     

    参考资料

    [1]XPath Examples. http://msdn2.microsoft.com/en-us/library/ms256086.aspx

    [2]XPath Tutorial http://www.zvon.org/xxl/XPathTutorial/Output/example1.html

    [3]XPath介绍 http://www.xml.org.cn/dispbbs.asp?boardID=14&ID=35493

    [4]XPath reference http://msdn2.microsoft.com/en-us/library/ms256115.aspx

    [5]XML Path Language (XPath)Version 1.0 http://www.w3.org/TR/xpath

    [6]XPath Tutorial http://www.w3schools.com/xpath/default.asp

  • 相关阅读:
    2019-7-3-WPF-使用-Composition-API-做高性能渲染
    2019-7-3-WPF-使用-Composition-API-做高性能渲染
    2018-8-10-win10-uwp-禁止编译器优化代码
    2018-8-10-win10-uwp-禁止编译器优化代码
    2018-2-13-wpf-如何使用-Magick.NET-播放-gif-图片
    2018-2-13-wpf-如何使用-Magick.NET-播放-gif-图片
    2019-8-31-Developing-Universal-Windows-Apps-开发UWA应用-问答
    2019-8-31-Developing-Universal-Windows-Apps-开发UWA应用-问答
    2019-3-1-WPF-从零开始开发-dotnet-Remoting-程序
    busybox
  • 原文地址:https://www.cnblogs.com/kokoliu/p/3747485.html
Copyright © 2011-2022 走看看