c# 使用HtmlAgilityPack解析Html
HtmlAgilityPack 是一個(gè)開(kāi)源的快速解析Html的C#類(lèi)庫(kù)。簡(jiǎn)單理解,它可以像解析Xml一樣,將Html根據(jù)XPATH轉(zhuǎn)化為一個(gè)個(gè)Node節(jié)點(diǎn),并支持調(diào)整節(jié)點(diǎn)以及節(jié)點(diǎn)的各種屬性。
多種方式加載Html
主要加載方式有3類(lèi):從網(wǎng)絡(luò)鏈接加載、從字符串文本中加載、從文件加載
var doc = new HtmlDocument(); //直接通過(guò)url加載 doc = new HtmlWeb().Load("https://www.baidu.com/"); //通過(guò)字符串加載 doc.LoadHtml(result); //通過(guò)html文件加載 可指定編碼方式 doc.Load(@"c://index.html",Encoding.UTF8)
HtmlNode常用方法
使用SelectNodes()和SelectSingleNode()方法(類(lèi)似解析XML格式數(shù)據(jù)的XmlDocument)來(lái)獲取的目標(biāo)節(jié)點(diǎn),分別對(duì)應(yīng)HtmlNodeCollection和HtmlNode兩個(gè)類(lèi)。
"http://"表示從根節(jié)點(diǎn)開(kāi)始查找,兩個(gè)斜杠"http://"表示查找所有childnodes;一個(gè)斜杠"/"表示只查找第一層的childnodes(即不查找grandchild);點(diǎn)斜杠"./"表示從當(dāng)前結(jié)點(diǎn)而不是根結(jié)點(diǎn)開(kāi)始查找(只在xpath最開(kāi)始出現(xiàn))
注意:
id class 屬性匹配大小寫(xiě)敏感
xpath匹配下標(biāo)從1開(kāi)始
1. 通過(guò)屬性和路徑匹配來(lái)選擇對(duì)應(yīng)的節(jié)點(diǎn)
var node = doc.DocumentNode; //選擇不包含class屬性的div節(jié)點(diǎn) var result = node.SelectNodes(".//div[not(@class)]"); //選擇不包含class和id屬性的div節(jié)點(diǎn) var result = node.SelectNodes(".//div[not(@class) and not(@id)]"); //選擇class中包含"expire"的span節(jié)點(diǎn) var result = node.SelectNodes(".//span[contains(@class,'expire')]"); //選擇class中不包含"expire"的span節(jié)點(diǎn) var result = node.SelectNodes(".//span[not(contains(@class,'expire'))]"); //選擇class="expire"的span節(jié)點(diǎn) var result = node.SelectNodes(".//span[@class='expire']"); //選擇id="expire"的div節(jié)點(diǎn)下第一個(gè)div節(jié)點(diǎn) var result = node.SelectSingleNode(".//div[@id='expire']/div[1]");
2. 獲取節(jié)點(diǎn)文本內(nèi)容
根據(jù)需求不同,通過(guò)不同的方式來(lái)獲取相應(yīng)的文本內(nèi)容。
OuterHtml:返回包含當(dāng)前節(jié)點(diǎn)在內(nèi)的所有Html
InnerHtml:返回當(dāng)前節(jié)點(diǎn)內(nèi)所有子節(jié)點(diǎn)Html
InnerText:返回當(dāng)前節(jié)點(diǎn)內(nèi)去除所有Html后的文本內(nèi)容
<div id="title"> <p> <a class="MainTitle" rel="external nofollow" rel="external nofollow" rel="external nofollow" >傅小灰</a> </p> </div>
以上面的Html為例
var node= doc.DocumentNode.SelectSingleNode("http://div[@id='title'/p]"); node.OuterHtml; //返回結(jié)果:<p><a class="MainTitle" rel="external nofollow" rel="external nofollow" rel="external nofollow" >傅小灰</a></p> node.InnerHtml; //返回結(jié)果:<a class="MainTitle" rel="external nofollow" rel="external nofollow" rel="external nofollow" >傅小灰</a> node.InnerText; //返回結(jié)果:傅小灰
3. 獲取/修改節(jié)點(diǎn)屬性值
以上面的Html舉例,我們獲取到了a標(biāo)簽為node節(jié)點(diǎn)。我們想要獲取a標(biāo)簽指向的鏈接地址,并修改為我們?cè)O(shè)定的地址。這里以href屬性舉例,同樣可以用在class/src/id等屬性上。
var node= doc.DocumentNode.SelectSingleNode("http://div[@id='title'/p/a]"); //第二個(gè)參數(shù)為找不到對(duì)應(yīng)屬性時(shí)返回的默認(rèn)值 var url = node.GetAttributeValue("href", "");//返回結(jié)果:https://www.cnblogs.com/cplemom/ //設(shè)置屬性值 node.SetAttributeValue("href", "http://www.cplemom.com/"); //獲取所有屬性值 var list = node.Attributes.ToList();
4. 刪除/替換節(jié)點(diǎn)
繼續(xù)以上面的Html舉例,我們獲取到了a標(biāo)簽為node節(jié)點(diǎn)。
對(duì)于我們不需要的內(nèi)容,我們只需要調(diào)用節(jié)點(diǎn)Remove方法即可。
var node= doc.DocumentNode.SelectSingleNode("http://div[@id='title'/p/a]"); node.Remove();//刪除節(jié)點(diǎn)
一個(gè)很常見(jiàn)的場(chǎng)景就是我們需要移除a標(biāo)簽,但是要在html上下文中保留a標(biāo)簽的文本。
PS : a標(biāo)簽內(nèi)的文本在HtmlDocument中其實(shí)是一個(gè)text類(lèi)型的node節(jié)點(diǎn)。所以我們可以通過(guò)刪除a標(biāo)簽,保留text標(biāo)簽的方式來(lái)完成目標(biāo)。
node.ParentNode.RemoveChild(node,true);
true表示留下a標(biāo)簽的子節(jié)點(diǎn)只刪除a標(biāo)簽,在這里就表示保留下“傅小灰”text節(jié)點(diǎn); false表示將此結(jié)點(diǎn)連同所有子節(jié)點(diǎn)一起刪除。
換個(gè)角度思考下,當(dāng)前node節(jié)點(diǎn)代表的是單個(gè)a標(biāo)簽,那么如果p標(biāo)簽下存在多個(gè)a標(biāo)簽需要處理,或者node節(jié)點(diǎn)指向的就是p標(biāo)簽?zāi)???dāng)然,我們可以通過(guò)獲取所有a標(biāo)簽然后循環(huán)處理的方式來(lái)實(shí)現(xiàn),但是還有沒(méi)有別的更好的處理方式呢?
這里提供一個(gè)思路,獲取所有的文本內(nèi)容,新建為一個(gè)text節(jié)點(diǎn),然后替換掉當(dāng)前節(jié)點(diǎn)。
node.ParentNode.ReplaceChild(HtmlNode.CreateNode(item.InnerText), node);
幾個(gè)常見(jiàn)使用場(chǎng)景和解決方案
1. 獲取所有的img標(biāo)簽
//通過(guò)Descendants獲取所有的子后代節(jié)點(diǎn)中的img標(biāo)簽 var list = node.Descendants("img"); //通過(guò)Xpath匹配獲取所有img標(biāo)簽 var list = node.SelectNodes("http://img");
2. 通過(guò)url訪問(wèn)時(shí)需要攜帶cookie等驗(yàn)證信息
有些頁(yè)面需要攜帶驗(yàn)證信息才能訪問(wèn),比如用戶中心,訂單列表等,這時(shí)候直接通過(guò)HtmlWeb類(lèi)獲取html會(huì)被拒絕。有個(gè)簡(jiǎn)單的方式就是通過(guò)HttpClient請(qǐng)求到對(duì)應(yīng)的html內(nèi)容,再使用HtmlDocument加載。其實(shí)HtmlWeb說(shuō)白了也是封裝的HttpWebRequest進(jìn)行網(wǎng)絡(luò)請(qǐng)求的,所以暴露一個(gè)委托給外部用以修改請(qǐng)求上下文。
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; }
總結(jié)
用到現(xiàn)在,個(gè)人感覺(jué)上面的方法已經(jīng)可以實(shí)現(xiàn)90%以上的的Html解析相關(guān)需求了,更多方便快捷的方法還是到官網(wǎng)的API文檔進(jìn)行了解吧。
以上就是c# 使用HtmlAgilityPack解析Html的詳細(xì)內(nèi)容,更多關(guān)于c# HtmlAgilityPack解析Html的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
學(xué)習(xí)Winform分組類(lèi)控件(Panel、groupBox、TabControl)
這篇文章主要和大家一起學(xué)習(xí)Winform分組類(lèi)控件,包括容器控件(Panel),分組框控件(groupBox)和選項(xiàng)卡控件(TabControl)等控件,感興趣的小伙伴們可以參考一下2016-05-05C#實(shí)現(xiàn)文件與Base64的相互轉(zhuǎn)換
本文主要介紹了C#實(shí)現(xiàn)文件與Base64的相互轉(zhuǎn)換,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06詳解ASP.NET中Identity的身份驗(yàn)證代碼
這篇文章主要介紹了ASP.NET Identity 的“多重”身份驗(yàn)證代碼,以及實(shí)現(xiàn)的原理講解,需要的朋友參考一下。2017-12-12解決安裝VS2008無(wú)法更改默認(rèn)路徑的問(wèn)題
這篇文章主要介紹了安裝VS2008無(wú)法更改默認(rèn)路徑的解決方法,需要的朋友可以參考下。2016-06-06C#生成設(shè)置范圍內(nèi)的Double類(lèi)型隨機(jī)數(shù)的方法
這篇文章主要介紹了C#生成設(shè)置范圍內(nèi)的Double類(lèi)型隨機(jī)數(shù)的方法,對(duì)于C#的初學(xué)者有很好的借鑒價(jià)值,需要的朋友可以參考下2014-08-08C#?winform中ComboBox數(shù)據(jù)綁定的兩種方法及效率詳解
這篇文章主要給大家介紹了關(guān)于C#?winform中ComboBox數(shù)據(jù)綁定的兩種方法及效率,Winform?ComboBox數(shù)據(jù)綁定是指將數(shù)據(jù)源中的數(shù)據(jù)與ComboBox控件進(jìn)行關(guān)聯(lián),需要的朋友可以參考下2023-08-08C#動(dòng)態(tài)加載組件后如何在開(kāi)發(fā)環(huán)境中調(diào)試詳解
這篇文章主要給大家介紹了關(guān)于C#動(dòng)態(tài)加載組件后如何在開(kāi)發(fā)環(huán)境中調(diào)試的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者使用C#具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03c# 調(diào)用.bat文件的實(shí)現(xiàn)代碼
c# 調(diào)用.bat文件主要利用了using System.Diagnostics;命名空間,大家可以參考下。2009-06-06C#基于Socket實(shí)現(xiàn)簡(jiǎn)單聊天室功能
這篇文章主要為大家詳細(xì)介紹了C#基于Socket實(shí)現(xiàn)簡(jiǎn)單聊天室功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02C#使用BitConverter與BitArray類(lèi)進(jìn)行預(yù)定義基礎(chǔ)類(lèi)型轉(zhuǎn)換
這篇文章介紹了C#使用BitConverter與BitArray類(lèi)進(jìn)行預(yù)定義基礎(chǔ)類(lèi)型轉(zhuǎn)換的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05