C#使用HtmlAgilityPack組件解析html文檔
一、HtmlAgilityPack介紹
參考:
GitHub:https://github.com/zzzprojects/html-agility-pack/releases
官網(wǎng):https://html-agility-pack.net/
https://www.nuget.org/packages/HtmlAgilityPack/
HtmlAgilityPack(以下簡稱HAP)是一個基于.Net的、第三方免費開源的微型類庫,主要用于在服務器端解析html文檔。
HtmlAgilityPack為網(wǎng)頁提供了標準的DOM API和XPath導航 。使用WebBrowser和HttpWebRequest下載的網(wǎng)頁可以用Html Agility Pack來解析。

Xpath表達式的參考文檔可見:XML基本概念XPath、XSLT與XQuery函數(shù)介紹
二、屬性和方法
HtmlAgilityPack中的HtmlNode類與XmlNode類差不多,HtmlDocument類與XmlDocument類差不多。
1、屬性:
- OwnerDocument:節(jié)點所在的HtmlDocument文檔
- Attributes: 獲取節(jié)點的屬性集合
- ParentNode:獲取該節(jié)點的父節(jié)點
- ChildNodes:獲取子節(jié)點集合(包括文本節(jié)點)
- FirstChild: 獲取第一個子節(jié)點
- LastChild: 獲取最后一個子節(jié)點
- Id: 獲取該節(jié)點的Id屬性
- Name:Html元素名
- NodeType: 獲取該節(jié)點的節(jié)點類型
- InnerHtml: 獲取該節(jié)點的Html代碼
- InnerText: 獲取該節(jié)點的內(nèi)容,與InnerHtml不同的地方在于它會過濾掉Html代碼,而InnerHtml是連Html代碼一起輸出
- OuterHtml: 整個節(jié)點的代碼
- PreviousSibling: 獲取前一個兄弟節(jié)點
- NextSibling: 獲取下一個兄弟節(jié)點
- HasAttributes :判斷該節(jié)點是否含有屬性
- HasChildNodes: 判斷該節(jié)點是否含有子節(jié)點
- HasClosingAttributes : 判斷該節(jié)點的關(guān)閉標簽是否含有屬性(</xxx class="xxx">)
- Closed:該節(jié)點是否已關(guān)閉(</xxx>)
- ClosingAttributes在關(guān)閉標簽的屬性集合StreamPosition: 該節(jié)點位于整個Html文檔的字符位置
- XPath: 根據(jù)節(jié)點返回該節(jié)點的XPath
2、方法:
- Load (string path): 從路徑中加載一個文檔
- SelectNodes (string xpath): 根據(jù)XPath獲取一個節(jié)點集合
- SelectSingleNode (string xpath): 根據(jù)XPath獲取唯一的一個節(jié)
- Ancestors (): 返回此元素的所有上級節(jié)點的集合。
- DescendantNodes (): 獲取所有子代節(jié)點
- Element (string name): 根據(jù)參數(shù)名獲取一個元素
- Elements (string name): 根據(jù)參數(shù)名獲取匹配的元素集合
- GetAttributeValue(string name, bool def): 幫助方法,用來獲取此節(jié)點的屬性的值(布爾類型)。如果未找到該屬性,則將返回默認值。
- ChildAttributes(string name): 獲取所有子元素的屬性(參數(shù)名要與元素名匹配)
- IsEmptyElement(string name): 確定是否一個空的元素節(jié)點。
- IsOverlappedClosingElement(string text): 確定是否文本對應于一個節(jié)點可以保留重疊的結(jié)束標記。
- AppendChild(HtmlNode newChild): 將參數(shù)元素追加到為調(diào)用元素的子元素(追加在最后)
- PrependChild(HtmlNode newChild): 將參數(shù)中的元素作為子元素,放在調(diào)用元素的最前面
- Clone(): 本節(jié)點克隆到一個新的節(jié)點
- CopyFrom(HtmlNode node): 創(chuàng)建重復的節(jié)點和其下的子樹。
- CreateNavigator(): 返回的一個對于此文檔的XPathNavigator
- CreateNode(string html): 靜態(tài)方法,允許用字符串創(chuàng)建一個新節(jié)點
- CreateRootNavigator(): 創(chuàng)建一個根路徑的XPathNavigator
- InsertAfter(HtmlNode newChild, HtmlNode refChild): 將一個節(jié)點插入到第二個參數(shù)節(jié)點的后面,與第二個參數(shù)是兄弟關(guān)系
- InsertBefore(HtmlNode newChild, HtmlNode refChild): 將一個節(jié)點插入到第二個參數(shù)節(jié)點的后面,與第二個參數(shù)是兄弟關(guān)系
- Remove(): 從父集合中移除調(diào)用節(jié)點
- SetAttributeValue(string name, string value): 設置調(diào)用節(jié)點的屬性
- WriteContentTo(): 將該節(jié)點的所有子級都保存到一個字符串中。
- WriteTo(): 將當前節(jié)點保存到一個字符串中。
- Save(string filename): 將HTML文檔保存到指定的路徑
三、用法舉例

下面是幾個簡單使用說明:
1、獲取網(wǎng)頁title:
doc.DocumentNode.SelectSingleNode("http://title").InnerText;//XPath中:“//title”表示所有title節(jié)點。SelectSingleNode用于獲取滿足條件的唯一的節(jié)點。2、獲取所有的超鏈接:
doc.DocumentNode.Descendants("a")3、獲取name為kw的input,也就是相當于getElementsByName():
var kwBox = doc.DocumentNode.SelectSingleNode("http://input[@name='kw']");示例:
private void Form1_Load(object sender, EventArgs e)
{
List<Result> list = new List<Result>();
HtmlWeb htmlWeb = new HtmlWeb();
htmlWeb.OverrideEncoding = Encoding.UTF8;//編碼,這里網(wǎng)上有些很多寫法都不正確
HtmlAgilityPack.HtmlDocument htmlDoc = htmlWeb.Load(@http://www.cnblogs.com/);
//選擇博客園首頁文章列表
htmlDoc.DocumentNode.SelectNodes("http://div[@id='post_list']/div[@class='post_item']").//雙斜杠“//”表示從跟節(jié)點開始查找
AsParallel().ToList().ForEach(ac =>
{
//抓取圖片,因為有空的,所以拿變量存起來
HtmlNode node = ac.SelectSingleNode(".//p[@class='post_item_summary']/a/img");
list.Add(new Result
{
url = ac.SelectSingleNode(".//a[@class='titlelnk']").Attributes["href"].Value,
title = ac.SelectSingleNode(".//a[@class='titlelnk']").InnerText,
//圖片如果為空,顯示默認圖片
img = node == null ? "http ://www.cnblogs.com//Content/img/avatar.png" : node.Attributes["src"].Value,
content = ac.SelectSingleNode(".//p[@class='post_item_summary']").InnerText
});
});
foreach (Result item in list)
{
this.listBox1.Items.Add(item.title);
}
}
/// <summary>
/// 頁面抓取結(jié)果
/// </summary>
public class Result
{
/// <summary>
/// 鏈接
/// </summary>
public string url { get; set; }
/// <summary>
/// 標題
/// </summary>
public string title { get; set; }
/// <summary>
/// 頭像地址
/// </summary>
public string img { get; set; }
/// <summary>
/// 正文內(nèi)容
/// </summary>
public string content { get; set; }
}示例2:下載微軟文檔
using HtmlAgilityPack;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace ConsoleApp4
{
internal class Program
{
private static void Main(string[] args)
{
//網(wǎng)頁地址:
string Url = "https://docs.microsoft.com/zh-cn/aspnet/mvc/overview/getting-started/getting-started-with-ef-using-mvc/implementing-inheritance-with-the-entity-framework-in-an-asp-net-mvc-application";
List<string> list = new List<string>(); ;
HtmlWeb htmlWeb = new HtmlWeb();
htmlWeb.OverrideEncoding = Encoding.UTF8;
HtmlDocument htmlDoc = htmlWeb.Load(Url);
HtmlNode node = htmlDoc.DocumentNode.SelectSingleNode("http://main[@id='main']");
//去掉英文翻譯
var a = node.SelectNodes("http://span[@class='sxs-lookup']");
foreach (HtmlNode b in a)
{
b.Remove();
}
string src = "";
//圖片相對路徑改成絕對路徑
var imgNode = node.SelectNodes("http://img[@data-linktype='relative-path']");
foreach (HtmlNode node1 in imgNode)
{
src = node1.GetAttributeValue("src", "");
var url = new Uri(htmlWeb.ResponseUri, src);
node1.SetAttributeValue("src", url.AbsoluteUri);
}
//鏈接路徑轉(zhuǎn)換
var hrefNode = node.SelectNodes("http://a[@data-linktype='relative-path']|//a[@data-linktype='absolute-path']");
foreach (HtmlNode node1 in hrefNode)
{
src = node1.GetAttributeValue("href", "");
var url = new Uri(htmlWeb.ResponseUri, src);
node1.SetAttributeValue("href", url.AbsoluteUri);
}
//找到所有的H2標簽,然后加上順序。
var h2Node = node.SelectNodes("http://h2");
var arr = new string[] { "一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二", "十三", "十四", "十五", "十六", "十七", "十八", "十九", "二十" };
if (h2Node != null)
{
for (int i = 0; i < h2Node.Count; i++)
{
h2Node[i].InnerHtml = arr[i] + "、" + h2Node[i].InnerHtml;
//找到所有的H3標簽,然后加上順序。
var h3Node = h2Node[i].SelectNodes("following-sibling::h2|following-sibling::h3");
if (h3Node is null)
break;
for (int j = 0; j < h3Node.Count; j++)
{
if (h3Node[j].Name == "h2")
break;
else
h3Node[j].InnerHtml = (j + 1) + "、" + h3Node[j].InnerHtml;
}
}
}
HtmlNode myNOde = htmlDoc.CreateElement("div");
//去掉前面無用的部分
var OK = node.SelectNodes("nav[1]/following-sibling::*");
myNOde.AppendChildren(OK);
//添加原文連接:
HtmlNode nodeOriUrl = htmlDoc.CreateElement("p");
nodeOriUrl.InnerHtml = "原文:<a href='" + htmlWeb.ResponseUri + "'>" + htmlWeb.ResponseUri + "</a>";
myNOde.PrependChild(nodeOriUrl);
//寫入到本地文件
TextWriter wr = new StreamWriter(@"aa.html");
myNOde.WriteTo(wr);
wr.Close();
}
}
}四、Fizzler.Systems.HtmlAgilityPack:
Hazz為HTMLAgilityPack實現(xiàn)CSS選擇器。它基于Fizzler,一個通用的CSS選擇器解析器和生成器庫。
Hazz以前稱為Fizzler.Systems.HtmlAgilityPack。
// Load the document using HTMLAgilityPack as normal
var html = new HtmlDocument();
html.LoadHtml(@"
<html>
<head></head>
<body>
<div>
<p class='content'>Fizzler</p>
<p>CSS Selector Engine</p></div>
</body>
</html>");
// Fizzler for HtmlAgilityPack is implemented as the
// QuerySelectorAll extension method on HtmlNode
var document = html.DocumentNode;
// yields: [<p class="content">Fizzler</p>]
document.QuerySelectorAll(".content");
// yields: [<p class="content">Fizzler</p>,<p>CSS Selector Engine</p>]
document.QuerySelectorAll("p");
// yields empty sequence
document.QuerySelectorAll("body>p");
// yields [<p class="content">Fizzler</p>,<p>CSS Selector Engine</p>]
document.QuerySelectorAll("body p");
// yields [<p class="content">Fizzler</p>]
document.QuerySelectorAll("p:first-child");到此這篇關(guān)于C#使用HtmlAgilityPack組件解析html文檔的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
DevExpress實現(xiàn)TreeList按條件隱藏節(jié)點CheckBox的方法
這篇文章主要介紹了DevExpress實現(xiàn)TreeList按條件隱藏節(jié)點CheckBox的方法,需要的朋友可以參考下2014-08-08
C#使用FileInfo和DirectoryInfo類來執(zhí)行文件和文件夾操作
System.IO.FileInfo?和?System.IO.DirectoryInfo?是C#中用于操作文件和文件夾的類,它們提供了許多有用的方法和屬性來管理文件和文件夾,這篇文章主要介紹了C#使用FileInfo和DirectoryInfo類來執(zhí)行文件和文件夾操作,需要的朋友可以參考下2023-08-08

