最近在弄網頁爬蟲這方面的,上網看到關於htmlagilitypack搭配scrapysharp的文章,於是決定試一試~
於是到https://www.nuget.org/packages/ScrapySharp去看看,
看到這句下載提示:To install ScrapySharp, run the following command in the Package Manager Console
PM> Install-Package ScrapySharp
接下去我就去找package manager console,(http://docs.nuget.org/docs/start-here/using-the-package-manager-console)
操作說明:From the Tools menu, select Library Package Manager and then click Package Manager Console.
發現還沒裝~@_@!!
那么就去裝一下插件吧!閱讀了這篇博文http://www.cnblogs.com/baiyu/archive/2011/09/07/2170028.html
一、 安裝Nuget
1. Visual studio 2012-> Tool-> Extension Manager。
2. 選擇Online Gallery,在右上角的搜索中輸入Nuget,之后按提示安裝即可。
3. 安裝之后菜單View-> Other windows中會出現Package Manager Console, 這是一個集成到VS中的控制台工具。
注意:在選擇ScrapySharp的版本的時候也要考慮htmlAgilityPack的版本
附:scrapySharp官網鏈接:https://www.nuget.org/packages/ScrapySharp
於是,繼續操作Tools->Library Package Manager->Package Manager Console
PM> Install-Package HtmlAgilityPack 正在安裝“HtmlAgilityPack 1.4.6”。 已成功安裝“HtmlAgilityPack 1.4.6”。 正在將“HtmlAgilityPack 1.4.6”添加到 WindowsFormsDemo0320。 已成功將“HtmlAgilityPack 1.4.6”添加到 WindowsFormsDemo0320。
PM> Install-Package ScrapySharp 正在嘗試解析依賴項“HtmlAgilityPack (≥ 1.4.6)”。 正在安裝“ScrapySharp 2.2.63”。 已成功安裝“ScrapySharp 2.2.63”。 正在將“ScrapySharp 2.2.63”添加到 WindowsFormsDemo0320。 已成功將“ScrapySharp 2.2.63”添加到 WindowsFormsDemo0320。
接下來開始進行抓取,
原始網頁是網易一新聞網頁:http://news.163.com/14/0413/18/9PNVIBV000014JB6.html
下面實現的效果是,抓取title標簽的內容和正文內容(也就是<div id="endText">…(捕捉<p></p>中間的內容)…</div>)
捕捉title的時候需要注意,有時候一個網頁不只一對title標簽!!
但是,其實網易新聞頁面顯示的標題存儲的標簽<h1 id="hltitle">……</h1>
所以提取標題的核心代碼為
String title = doc.DocumentNode.SelectSingleNode("//h1[@id='h1title']").InnerText;
捕捉正文內容的核心代碼:
html.CssSelect("p").CssSelectAncestors("div#endText");
下面看下該新聞頁面正文部分的html代碼:
<div id="endText"></p><p>人民網蘭州4月13日電 蘭州市今天下午召開新聞發布會,初步查明了導致自流溝內水體苯超標的原因。根據環保專家現場初步分析判斷,周邊地下含油污水是引起自流溝內水體苯超標的直接原因。</p><p>根據目前的調查情況初步判定,自流溝周邊地下含油污水形成的原因有三點:一是原蘭化公司原料動力廠原油蒸餾車間R205A#渣油罐曾於1987年12月28日8時50分發生物理爆破事故,罐體破裂造成90立方渣油瀉出,其中有34噸渣油跑料未能回收,滲入地下;二是原蘭化公司原料動力廠原油蒸餾車間泵B-113出口總管曾於2002年4月3日發生開裂着火,泄漏的渣油及救火過程中產生的大量消防污水滲入地下。</p><p>另據中新網蘭州4月13日電 蘭州市“4·11”局部自來水苯指標超標事故應急處置領導小組副組長鄭志強13日說,調查組從11日下午3時開始展開調查工作,采取開挖深坑的方法,查找到了導致水體苯超標的方位。根據環保專家現場初步分析判斷,周邊地下含油污水是引起自流溝內水體苯超標的直接原因。</p><p>蘭州官方通報稱,根據目前的調查情況初步判定,自流溝周邊地下含油污水的形成原因有兩個:</p><p>一是原蘭化公司原料動力廠原油蒸餾車間R205A#渣油罐(該址原為蘭化公司原料動力廠250萬噸/年煉油裝置,該裝置建於1982年,2003年停用,2006年拆除。拆除后,在原址建成現有的40萬噸/年芳烴抽提裝置,罐區設計分別儲存餾份油、輕油、渣油),曾於1987年12月28日8時50分發生物理爆破事故,罐體破裂造成90立方渣油泄出,其中有34噸渣油跑料未能回收,滲入地下。</p><p><!-- AD200x300_2 --> <div class="gg200x300"> <iframe src="http://g.163.com/r?site=netease&affiliate=news&cat=article&type=logo300x250&location=13" width="300" height="250" frameborder="no" border="0" marginwidth="0" marginheight="0" scrolling="no"> </iframe> </div><p>二是原蘭化公司原料動力廠原油蒸餾車間泵B—113出口總管曾於2002年4月3日發生開裂着火,泄漏的渣油(具體數量當時未統計)及救火過程中產生的大量消防污水滲入地下。</p><p>鄭志強說,目前蘭州石化現有生產裝置及罐區運行正常,未發現物料及產品泄漏現象。生產區域內雨排井、化污系統水封井未發現物料泄漏現象,消防井內發現有少量飄油。</p><p>事故調查組下一步調查工作的重點是,對從開挖深坑中提取的含油廢水組份進行化驗,進一步從技術層面核實地下含油污水與自流溝內苯超標水體的關聯性。同時,對4號、3號自流溝內的具體泄漏點位進行實地勘查核實,並對造成局部自來水苯超標事件的相關責任單位和責任人進行進一步的調查取證。(完)</p>
<div class="ep-source cDGray"> <span class="left"><a href="http://news.163.com/"><img src="http://img1.cache.netease.com/cnews/css13/img/end_news.png" alt="netease" width="13" height="12" class="icon"></a> 本文來源:人民網 作者:高翔、銀燕、苗亮軍</span> <span class="ep-editor">責任編輯:NN102</span>
</div> </div>
下面貼一下實現的核心代碼(但是編碼處理部分代碼沒有貼出)
添加 :using ScrapySharp.Extensions;
namespace HtmlAgilityDemo { class Program { static void Main(string[] args) { var uri = new Uri("http://news.163.com/14/0413/18/9PNVIBV000014JB6.html"); var browser1 = new ScrapingBrowser(); var html1 = browser1.DownloadString(uri); var doc = new HtmlDocument(); doc.LoadHtml(html1); var html = doc.DocumentNode; var title = html.CssSelect("title"); foreach (var htmlNode in title) { Console.WriteLine(htmlNode.InnerText); }
var ps = html.CssSelect("p").CssSelectAncestors("div#endText"); foreach (var htmlNode in ps) { Console.WriteLine(htmlNode.InnerHtml); } } } }
運行后輸出:
蘭州官方公布自流溝周邊地下含油污水形成原因_網易新聞中心 人民網蘭州4月13日電 蘭州市今天下午召開新聞發布會,初步查明了導致自流溝內水體苯超標的原因。根據環保專家現場初步分析判斷,周邊地下含油污水是引起自流溝內水體苯超標的直接原因。根據目前的調查情況初步判定,自流溝周邊地下含油污水形成的原因有三點:一是原蘭化公司原料動力廠原油蒸餾車間R205A#渣油罐曾於1987年12月28日8時50分發生物理爆破事故,罐體破裂造成90立方渣油瀉出,其中有34噸渣油跑料未能回收,滲入地下;二是原蘭化公司原料動力廠原油蒸餾車間泵B-113出口總管曾於2002年4月3日發生開裂着火,泄漏的渣油及救火過程中產生的大量消防污水滲入地下。另據中新網蘭州4月13日電 蘭州市“4·11”局部自來水苯指標超標事故應急處置領導小組副組長鄭志強13日說,調查組從11日下午3時開始展開調查工作,采取開挖深坑的方法,查找到了導致水體苯超標的方位。根據環保專家現場初步分析判斷,周邊地下含油污水是引起自流溝內水體苯超標的直接原因。蘭州官方通報稱,根據目前的調查情況初步判定,自流溝周邊地下含油污水的形成原因有兩個:一是原蘭化公司原料動力廠原油蒸餾車間R205A#渣油罐(該址原為蘭化公司原料動力廠250萬噸/年煉油裝置,該裝置建於1982年,2003年停用,2006年拆除。拆除后,在原址建成現有的40萬噸/年芳烴抽提裝置,罐區設計分別儲存餾份油、輕油、渣油),曾於1987年12月28日8時50分發生物理爆破事故,罐體破裂造成90立方渣油泄出,其中有34噸渣油跑料未能回收,滲入地下。<!-- AD200x300_2 --> 二是原蘭化公司原料動力廠原油蒸餾車間泵B—113出口總管曾於2002年4月3日發生開裂着火,泄漏的渣油(具體數量當時未統計)及救火過程中產生的大量消防污水滲入地下。鄭志強說,目前蘭州石化現有生產裝置及罐區運行正常,未發現物料及產品泄漏現象。生產區域內雨排井、化污系統水封井未發現物料泄漏現象,消防井內發現有少量飄油。事故調查組下一步調查工作的重點是,對從開挖深坑中提取的含油廢水組份進行化驗,進一步從技術層面核實地下含油污水與自流溝內苯超標水體的關聯性。同時,對4號、3號自流溝內的具體泄漏點位進行實地勘查核實,並對造成局部自來水苯超標事件的相關責任單位和責任人進行進一步的調查取證。(完) 本文來源:人民網 作者:高翔、銀燕、苗亮軍 責任編輯:NN102
然后看下輸出,發現出現殘留【<!-- AD200x300_2 --> 】
部分注釋代碼未被清除,那么處理一下,
foreach (HtmlNode nodeScripte in node.Descendants("script").ToList())
{ nodeScripte.Remove(); } foreach (HtmlNode nodeStyle in node.Descendants("style").ToList()) { nodeStyle.Remove(); } foreach (HtmlNode nodeComment in node.Descendants("//comment()").ToList()) { nodeComment.Remove(); }
發現嵌套在其中的注釋標簽用上面的方法無法清除干凈。
那么采用下面方法,
foreach(var script in doc.DocumentNode.Descendants("script").ToArray())
{ script.Remove();
} foreach(var style in doc.DocumentNode.Descendants("style").ToArray())
{ style.Remove();
} foreach(var comment in doc.DocumentNode.SelectNodes("//comment()").ToArray())
{ comment.Remove();
}
運行后發現,已經清除干凈。
把所有的script、style標簽從dom樹中去掉(為了解決迭代器在工作時不能從集合中Remove元素的問題,使用ToArray()轉換為數組再遍歷)。
HtmlAgilityPack是使用XPath語法,"//comment()"在XPath中表示“所有注釋節點”。
一些相關的語句:
1、獲取網頁title:doc.DocumentNode.SelectSingleNode("//title").InnerText;
解釋:XPath中“//title”表示所有title節點。SelectSingleNode用於獲取滿足條件的唯一的節點。
2、獲取所有的超鏈接:doc.DocumentNode.Descendants("a")
3、獲取name為kw的input,也就是相當於getElementsByName():
var kwBox = doc.DocumentNode.SelectSingleNode("//input[@name='kw']");
解釋:"//input[@name='kw']"也是XPath的語法,表示:name屬性等於kw的input標簽。
4、其他:
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");
參考鏈接:
http://www.cnblogs.com/rupeng/archive/2012/02/07/2342012.html
http://www.cnblogs.com/cappuccino/p/3403495.html
http://www.cnblogs.com/dc-lancer/archive/2013/03/27/2985163.html
http://www.cnblogs.com/sswwsw/archive/2012/12/06/2805097.html
http://www.cnblogs.com/linfei721/archive/2013/05/08/3066697.html
http://www.cnblogs.com/cxlings/archive/2013/05/31/3110858.html