服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - c# 使用HtmlAgilityPack解析Html

c# 使用HtmlAgilityPack解析Html

2022-10-24 11:44傅小灰 C#

这篇文章主要介绍了c# 如何使用HtmlAgilityPack解析Html,帮助大家利用c#进行爬虫,感兴趣的朋友可以了解下

HtmlAgilityPack 是一个开源的快速解析Html的C#类库。简单理解,它可以像解析Xml一样,将Html根据XPATH转化为一个个Node节点,并支持调整节点以及节点的各种属性。

传送门:#4f445015d1abe79a84fc9809c8294afc# | Github源码

多种方式加载Html

主要加载方式有3类:从网络链接加载、从字符串文本中加载、从文件加载

?
1
2
3
4
5
6
7
var doc = new HtmlDocument();
//直接通过url加载
doc = new HtmlWeb().Load("https://www.baidu.com/");
//通过字符串加载
doc.LoadHtml(result);
//通过html文件加载 可指定编码方式
doc.Load(@"c://index.html",Encoding.UTF8)

HtmlNode常用方法

使用SelectNodes()和SelectSingleNode()方法(类似解析XML格式数据的XmlDocument)来获取的目标节点,分别对应HtmlNodeCollection和HtmlNode两个类。

"//"表示从根节点开始查找,两个斜杠"//"表示查找所有childnodes;一个斜杠"/"表示只查找第一层的childnodes(即不查找grandchild);点斜杠"./"表示从当前结点而不是根结点开始查找(只在xpath最开始出现)

注意:

id class 属性匹配大小写敏感
xpath匹配下标从1开始

1. 通过属性和路径匹配来选择对应的节点

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var node = doc.DocumentNode;
 
//选择不包含class属性的div节点
var result = node.SelectNodes(".//div[not(@class)]");
 
//选择不包含class和id属性的div节点
var result = node.SelectNodes(".//div[not(@class) and not(@id)]");
 
//选择class中包含"expire"的span节点
var result = node.SelectNodes(".//span[contains(@class,'expire')]");
 
//选择class中不包含"expire"的span节点
var result = node.SelectNodes(".//span[not(contains(@class,'expire'))]");
 
//选择class="expire"的span节点
var result = node.SelectNodes(".//span[@class='expire']");
 
//选择id="expire"的div节点下第一个div节点
var result = node.SelectSingleNode(".//div[@id='expire']/div[1]");

2. 获取节点文本内容

根据需求不同,通过不同的方式来获取相应的文本内容。
OuterHtml:返回包含当前节点在内的所有Html
InnerHtml:返回当前节点内所有子节点Html
InnerText:返回当前节点内去除所有Html后的文本内容

?
1
2
3
4
5
<div id="title">
  <p>
   <a class="MainTitle" href="https://www.cnblogs.com/cplemom/" rel="external nofollow" rel="external nofollow" rel="external nofollow" >傅小灰</a>
  </p>
</div>

以上面的Html为例

?
1
2
3
4
5
6
7
var node= doc.DocumentNode.SelectSingleNode("//div[@id='title'/p]");
 
node.OuterHtml; //返回结果:<p><a class="MainTitle"href="https://www.cnblogs.com/cplemom/" rel="external nofollow" rel="external nofollow" rel="external nofollow" >傅小灰</a></p>
 
node.InnerHtml; //返回结果:<a class="MainTitle"href="https://www.cnblogs.com/cplemom/" rel="external nofollow" rel="external nofollow" rel="external nofollow" >傅小灰</a>
 
node.InnerText; //返回结果:傅小灰

3. 获取/修改节点属性值

以上面的Html举例,我们获取到了a标签为node节点。我们想要获取a标签指向的链接地址,并修改为我们设定的地址。这里以href属性举例,同样可以用在class/src/id等属性上。

?
1
2
3
4
5
6
7
8
9
10
var node= doc.DocumentNode.SelectSingleNode("//div[@id='title'/p/a]");
 
//第二个参数为找不到对应属性时返回的默认值
var url = node.GetAttributeValue("href", "");//返回结果:https://www.cnblogs.com/cplemom/
 
//设置属性值
node.SetAttributeValue("href", "http://www.cplemom.com/");
 
//获取所有属性值
var list = node.Attributes.ToList();

4. 删除/替换节点

继续以上面的Html举例,我们获取到了a标签为node节点。
对于我们不需要的内容,我们只需要调用节点Remove方法即可。

?
1
2
3
var node= doc.DocumentNode.SelectSingleNode("//div[@id='title'/p/a]");
 
node.Remove();//删除节点

一个很常见的场景就是我们需要移除a标签,但是要在html上下文中保留a标签的文本。
PS : a标签内的文本在HtmlDocument中其实是一个text类型的node节点。所以我们可以通过删除a标签,保留text标签的方式来完成目标。

?
1
node.ParentNode.RemoveChild(node,true);

true表示留下a标签的子节点只删除a标签,在这里就表示保留下“傅小灰”text节点; false表示将此结点连同所有子节点一起删除。

换个角度思考下,当前node节点代表的是单个a标签,那么如果p标签下存在多个a标签需要处理,或者node节点指向的就是p标签呢?当然,我们可以通过获取所有a标签然后循环处理的方式来实现,但是还有没有别的更好的处理方式呢?

这里提供一个思路,获取所有的文本内容,新建为一个text节点,然后替换掉当前节点。

?
1
node.ParentNode.ReplaceChild(HtmlNode.CreateNode(item.InnerText), node);

几个常见使用场景和解决方案

1. 获取所有的img标签

?
1
2
3
4
5
6
//通过Descendants获取所有的子后代节点中的img标签
var list = node.Descendants("img");
 
 
//通过Xpath匹配获取所有img标签
var list = node.SelectNodes("//img");

2. 通过url访问时需要携带cookie等验证信息

有些页面需要携带验证信息才能访问,比如用户中心,订单列表等,这时候直接通过HtmlWeb类获取html会被拒绝。有个简单的方式就是通过HttpClient请求到对应的html内容,再使用HtmlDocument加载。其实HtmlWeb说白了也是封装的HttpWebRequest进行网络请求的,所以暴露一个委托给外部用以修改请求上下文。

?
1
2
3
4
5
6
7
8
9
10
var web = new HtmlWeb();
web.PreRequest = new HtmlWeb.PreRequestHandler(GetRequest);
var node = web.Load("https://www.cplemom.com/");
 
public static bool GetRequest(HttpWebRequest req)
{
  req.Headers.Add("Host", "www.cplemom.com");
    req.Headers.Add("Cookie", "xxxxxxxxxxxxx");
  return true;
}

总结

用到现在,个人感觉上面的方法已经可以实现90%以上的的Html解析相关需求了,更多方便快捷的方法还是到官网的API文档进行了解吧。

以上就是c# 使用HtmlAgilityPack解析Html的详细内容,更多关于c# HtmlAgilityPack解析Html的资料请关注服务器之家其它相关文章!

原文链接:https://www.cnblogs.com/cplemom/p/13388613.html

延伸 · 阅读

精彩推荐
  • C#C#将PPT文件转换成PDF文件

    C#将PPT文件转换成PDF文件

    今天小编就为大家分享一篇关于C#将PPT文件转换成PDF文件,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看...

    chenqiangdage11602022-03-08
  • C#轻松学习C#的String类

    轻松学习C#的String类

    轻松学习C#的String类,小编也是第一次接触C#的String类,感兴趣的小伙伴们可以参考一下,大家一起学习。...

    丿木呈广予口贝10722021-11-03
  • C#C#实现根据实体类自动创建数据库表

    C#实现根据实体类自动创建数据库表

    本文主要介绍了C#通过自定义特性实现根据实体类自动创建数据库表的方法。具有很好的参考价值,需要的朋友一起来看下吧...

    天碼行空5082021-12-15
  • C#C#信号量用法简单示例

    C#信号量用法简单示例

    这篇文章主要介绍了C#信号量用法,结合简单C#控制台应用程序形式分析了信号量的功能、定义、调用、释放等操作技巧,需要的朋友可以参考下...

    kagula10822021-11-30
  • C#C# winform实现登陆次数限制

    C# winform实现登陆次数限制

    这篇文章主要介绍了C# winform实现登陆次数限制,相信大家都遇到过网站在用户多次输错密码之后会自动把账户冻结的情况,这种功能如何实现,下面小编为...

    net小伙10672021-11-21
  • C#详解C#之委托

    详解C#之委托

    这篇文章主要介绍了C#委托的含义以及用法,文中代码非常详细,帮助大家更好的理解和学习...

    千金不如一默3442022-09-09
  • C#C#实现在控制台输入密码显示星号的方法

    C#实现在控制台输入密码显示星号的方法

    这篇文章主要介绍了C#实现在控制台输入密码显示星号的方法,感兴趣的小伙伴们可以参考一下...

    一个人的长征9342021-11-18
  • C#c# 对CSV文件操作(写入、读取、修改)

    c# 对CSV文件操作(写入、读取、修改)

    这篇文章主要介绍了c# 如何对CSV文件操作,帮助大家更好的理解和学习C#,感兴趣的朋友可以了解下...

    张中华6122022-10-07