惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
The Exploit Database - CXSecurity.com
F
Fortinet All Blogs
U
Unit 42
F
Full Disclosure
雷峰网
雷峰网
博客园 - 司徒正美
云风的 BLOG
云风的 BLOG
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Tailwind CSS Blog
The Cloudflare Blog
Last Week in AI
Last Week in AI
罗磊的独立博客
D
DataBreaches.Net
C
Check Point Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
O
OpenAI News
C
CXSECURITY Database RSS Feed - CXSecurity.com
aimingoo的专栏
aimingoo的专栏
S
Security @ Cisco Blogs
大猫的无限游戏
大猫的无限游戏
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
S
SegmentFault 最新的问题
NISL@THU
NISL@THU
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The Hacker News
The Hacker News
Webroot Blog
Webroot Blog
Security Latest
Security Latest
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Google DeepMind News
Google DeepMind News
酷 壳 – CoolShell
酷 壳 – CoolShell
N
News | PayPal Newsroom
P
Proofpoint News Feed
B
Blog RSS Feed
MongoDB | Blog
MongoDB | Blog
C
Cybersecurity and Infrastructure Security Agency CISA
N
News and Events Feed by Topic
Google Online Security Blog
Google Online Security Blog
H
Help Net Security
Spread Privacy
Spread Privacy
T
Threat Research - Cisco Blogs
GbyAI
GbyAI
I
Intezer
Application and Cybersecurity Blog
Application and Cybersecurity Blog
M
MIT News - Artificial intelligence
Vercel News
Vercel News
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
IT之家
IT之家
MyScale Blog
MyScale Blog
腾讯CDC

博客园 - 唐朝程序员

推荐一个winform 界面交互类库转 DBCC SHOWCONTIG、DBCC DBREINDEX。 SQL Server2005索引碎片分析和解决方法 微软自带的防反编译工具dotfuscator.exe的使用 在HttpModule中使用gzip,deflate协议对aspx页面进行压缩(转) SQL查询重复数据和清除重复数据 lucene 笔记 SqlServer的汉字转拼音码的函数 windows系统事件查询 2010考研冲刺必备 2010公务员考试必备资料 url重写适用html为伪静态后真实的html无法访问的解决方法 SQL的 优化 (某篇的精简版) SQL 优化 (某篇的精简版) U影资源网原域名被封了,现在叫狐库网,启用了新的域名 vs2008 下载地址以及正式版序列号 Windows XP和Office2003通过正版验证,免去黑屏之忧 NOKIA诺基亚PC套件在2003系统上的安装方法 在.net 2.0 中使用ftp
some things
唐朝程序员 · 2014-05-23 · via 博客园 - 唐朝程序员

////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