1. 程式人生 > >C#+HtmlAgilityPack+XPath帶你採集資料(以採集天氣資料為例子)

C#+HtmlAgilityPack+XPath帶你採集資料(以採集天氣資料為例子)

  第一次接觸HtmlAgilityPack是在5年前,一些意外,讓我從技術部門臨時調到銷售部門,負責建立一些流程和尋找潛在客戶,最後在阿里巴巴找到了很多客戶資訊,非常全面,剛開始是手動複製到Excel,是真尼瑪的累,雖然那個時候C#還很菜,也想能不能通過程式來批量獲取(所以平時想法要多才好)。幾經周折,終於發現了HtmlAgilityPack神器,這幾年也用HtmlAgilityPack採集了很多型別資料,特別是足球賽事資料庫的資料採集以及天氣資料採集,都是使用HtmlAgilityPack,所以把自己的使用過程總結下來,分享給大家,讓更多人接觸和學會使用,給自己的工作帶來遍歷。

  今天的主要內容是HtmlAgilityPack的基本介紹、使用,實際程式碼。最後我們以採集天氣資料為例子,來介紹實際的採集分析過程和簡單的程式碼。我們將在下一篇文章中開源該天氣資料庫和C#操作程式碼。採集核心就只是在這裡介紹,其實核心程式碼都有了,自己加工下就可以了,同時也免費對有需要的人開放。至於具體詳情,請關注下一篇文章。

 

1.HtmlAgilityPack簡介

  HtmlAgilityPack是一個開源的解析HTML元素的類庫,最大的特點是可以通過XPath來解析HMTL,如果您以前用C#操作過XML,那麼使用起HtmlAgilityPack也會得心應手。目前最新版本為1.4.6,下載地址如下:http://htmlagilitypack.codeplex.com/ 目前穩定的版本是1.4.6,上一次更新還是2012年,所以很穩定,基本功能全面,也沒必要更新了。 

  提到HtmlAgilityPack,就必須要介紹一個輔助工具,不知道其他人在使用的時候,是如何分析頁面結構的。反正我是使用官方提供的一個叫做HAPExplorer的工具。非常有用。下面我們在使用的時候會介紹如何使用。   

2.XPath技術介紹與使用

2.1 XPath介紹

  XPath即為XML路徑語言,它是一種用來確定XML(標準通用標記語言的子集)文件中某部分位置的語言。XPath基於XML的樹狀結構,提供在資料結構樹中找尋節點的能力。起初 XPath 的提出的初衷是將其作為一個通用的、介於XPointer與XSL間的語法模型。但是 XPath 很快的被開發者採用來當作小型查詢語言。

  XPath是W3C的一個標準。它最主要的目的是為了在XML1.0或XML1.1文件節點樹中定位節點所設計。目前有XPath1.0和XPath2.0兩個版本。其中Xpath1.0是1999年成為W3C標準,而XPath2.0標準的確立是在2007年。W3C關於XPath的英文詳細文件請見:

http://www.w3.org/TR/xpath20/

2.2 XPath的路徑表達

  XPath是XML的查詢語言,和SQL的角色很類似。以下面XML為例,介紹XPath的語法。下面的一些資料是幾年前學習這個的時候,從網路以及部落格園獲取的一些資料,暫時找不到出處,例子和文字基本都是借鑑,再次謝過。如果大家發現類似的一起文章,告訴我連結,我加上引用。下面的Xpath的相關表達也很基礎,基本足夠用了。

<?xml version="1.0"encoding="ISO-8859-1"?>
<catalog>
<cd country="USA">
<title>Empire Burlesque</title>
<artist>Bob Dylan</artist>
<price>10.90</price>
</cd>
</catalog>

定位節點:XML是樹狀結構,類似檔案系統內資料夾的結構,XPath也類似檔案系統的路徑命名方式。不過XPath是一種模式(Pattern),可以選出XML檔案中,路徑符合某個模式的所有節點出來。例如要選catalog底下的cd中所有price元素可以用:

/catalog/cd/price

  如果XPath的開頭是一個斜線(/)代表這是絕對路徑。如果開頭是兩個斜線(//)表示檔案中所有符合模式的元素都會被選出來,即使是處於樹中不同的層級也會被選出來。以下的語法會選出檔案中所有叫做cd的元素(在樹中的任何層級都會被選出來)://cd

選擇未知的元素:使用星號(*)可以選擇未知的元素。下面這個語法會選出/catalog/cd的所有子元素:  

/catalog/cd/*

  以下的語法會選出所有catalog的子元素中,包含有price作為子元素的元素。

/catalog/*/price

  以下的語法會選出有兩層父節點,叫做price的所有元素。

/*/*/price

  要注意的是,想要存取不分層級的元素,XPath語法必須以兩個斜線開頭(//),想要存取未知元素才用星號(*),星號只能代表未知名稱的元素,不能代表未知層級的元素。

選擇分支:使用中括號可以選擇分支。以下的語法從catalog的子元素中取出第一個叫做cd的元素。XPath的定義中沒有第0元素這種東西。

/catalog/cd[1]

以下語法選擇catalog中的最後一個cd元素:(XPathj並沒有定義first()這種函式喔,用上例的[1]就可以取出第一個元素。

/catalog/cd[last()]

以下語法選出price元素的值等於10.90的所有/catalog/cd元素

/catalog/cd[price=10.90]

選擇屬性:在XPath中,除了選擇元素以外,也可以選擇屬性。屬性都是以@開頭。例如選擇檔案中所有叫做country的屬性:

//@country

以下語法選擇出country屬性值為UK的cd元素

//cd[@country='UK']

3.採集天氣網站案例

3.1 需求分析

  我們要採集的是全國各地城市的天氣資訊,網站為:http://www.tianqihoubao.com/,該網站資料分為2種類型,1個是歷史資料,覆蓋範圍為2011年至今,1個是天氣預報的資料,歷史資料是天氣後報,也就是實際的天氣資料。採集的範圍必須覆蓋全國主要城市,最好是所有的城市。通過分析該網站的頁面,的確是滿足要求。天氣資訊,包括實際的天氣狀況,風力狀況以及氣溫狀況情況,包括最低和最高區間。

  結合基本要求,我們進入網站,分析一些大概特點,以及主要頁面的結構。

3.2 網站頁面結構分析

  要採集大量的資訊,必須對網站頁面進行詳細的分析和總結。因為機器採集不是人工,需要動態構造URL,請求或者頁面html,然後進行解析。所以分析網站頁面結構是第一步,也是很關鍵的一步。我們首先進入到總的歷史頁面:http://www.tianqihoubao.com/lishi/,如下圖:

  很明顯,這個總的頁面按省份進行了分開,可以看到每個省份、地級市名稱的連結中,都是固定格式,只不過拼音縮寫不同而已。而且每個省份的第一個城市為省會城市。這一點要注意,程式中要區分省會城市和其他地級城市。當然省會城市也可以省略,畢竟只有30多個,手動標記也很快的事情。這個頁面我們將主要採集省份的縮寫資訊,然後我們選擇一個省份,點選進去,看每個省份具體的城市資訊,如我們選擇遼寧省:http://www.tianqihoubao.com/lishi/ln.htm如下圖:

  同樣,每個省份下面的地區也有單獨的連結,格式和上面的類似,按照城市拼音。我們看到每個省份下面,有大的地級行政區,每個地級市區後面細分了小的縣市區。我們隨意點選大連市的連結,進去看看具體的天氣歷史資訊:

   該頁面包括了城市2011年1月到2015年至今的歷史資料,按月分開。連結的特點也很固定,包括了城市名稱的拼音和年份月份資訊。所以構造這個連結就很容易了。下面看看每個月份的情況:

   廣告我遮蔽了一些,手動給抹掉吧。每個城市的每個月的天氣資訊比較簡單,直接表格填充了資料,日期,天氣狀況,氣溫和風力。這幾步都是按照頁面的連結一步一步引導過來的,所以上述流程清楚了,要採集的資訊也清楚了,有了大概的思路:

  先採集整個省份的拼音程式碼,然後依次獲取每個省份每個地級市,以及對應縣級市的名稱和拼音程式碼,最後迴圈每個縣級市,按照月份獲取所有歷史資料。下面將重點分析幾個頁面的節點情況,就是如何用HtmlAgilityPack和Xpath來獲取你要的資料資訊,至於儲存到資料庫,八仙過海各顯神通吧,我用的是XCode元件。

3.3 分析省-縣市結構頁面

  還是以遼寧省為例:http://www.tianqihoubao.com/lishi/ln.htm ,開啟頁面,右鍵獲取網頁原始碼後,貼上到 HAPExplorer 中,也可以直接在HAPExplorer 中開啟連結,如下面的動畫演示:

  我們可以看到,右側的XPath地址,div結束後,下面都是dl標籤,就是我們要採集的行了。下面我們用程式碼來獲取上述結構。先看看獲取頁面原始碼的程式碼:

public static string GetWebClient(string url)
{
	string strHTML = "";
	WebClient myWebClient = new WebClient();            
	Stream myStream = myWebClient.OpenRead(url);
	StreamReader sr = new StreamReader(myStream, Encoding.Default);//注意編碼
	strHTML = sr.ReadToEnd();
	myStream.Close();
	return strHTML;
}

   下面是分析每個省份下屬縣市區的程式,限於篇幅我們省掉了資料庫部分,只採集城市和拼音程式碼,並輸出:

/// <summary>新增省級-地區-縣市 的城市資訊,注意 省會城市 標記5</summary>
/// <param name="cityCode">省份程式碼</param>
public static void ParsePageByArea(String cityCode)
{
	//更加連結格式和省份程式碼構造URL
	String url = String.Format("http://www.tianqihoubao.com/lishi/{0}.htm", cityCode);
	//下載網頁原始碼 
	var docText = HtmlHelper.GetWebClient(url);
	//載入原始碼,獲取文件物件
	var doc = new HtmlDocument(); doc.LoadHtml(docText);
	//更加xpath獲取總的物件,如果不為空,就繼續選擇dl標籤
	var res = doc.DocumentNode.SelectSingleNode(@"/html[1]/body[1]/div[1]/div[6]/div[1]/div[1]/div[3]");
	if (res != null)
	{
		var list = res.SelectNodes(@"dl");//選擇標籤陣列
		if (list.Count < 1) return;
		foreach (var item in list)
		{
			var dd = item.SelectSingleNode(@"dd").SelectNodes("a");
			foreach (var node in dd)
			{
				var text = node.InnerText.Trim();
				//拼音程式碼要從href屬性中進行分割提取
				var herf = node.Attributes["href"].Value.Trim().Split('/', '.');
				Console.WriteLine("{0}:{1}", text, herf[herf.Length - 2]);
			}
		}
	}
}

 我們以遼寧為例,呼叫程式碼:ParsePageByArea("ln");結果如下:

3.4 分析城市單月的歷史天氣頁面

  這也是最重要核心的一個要分析的頁面。我們以大連市2011年8月份為例:http://www.tianqihoubao.com/lishi/dalian/month/201108.html,我們要找到我們需要採集的資訊節點,如下圖所示的動畫演示,其實這個過程習慣幾次就好了,每一次點選節點後,要觀察右邊的內容是不是我們想要的,還可以通過滾動條的長度判斷大概的長度。 

   這裡不是直接從URL載入,由於編碼原因,URL載入會有亂碼,所以我是手動輔助原始碼到HAPExplorer中的,效果一樣,所以直接在獲取頁面原始碼的時候,要注意編碼問題。總的過程比較簡單,還是查詢到Table標籤的位置,因為那裡儲存了所需要的資料,每一行每一列都非常標準。過程類似,我們直接更加XPath找到Table,然後一次獲取每行,每列,進行對應即可,看程式碼,都進行了詳細的註釋:

/// <summary>採集單個城市單個月的歷史天氣資料</summary>
/// <param name="cityCode">城市拼音程式碼</param>
/// <param name="year">年份</param>
/// <param name="month">月份</param>
public static void ParsePageByCityMonth(String cityCode, Int32 year, Int32 month)
{
	//更加拼音程式碼,月份資訊構造URL
	String url = String.Format("http://www.tianqihoubao.com/lishi/{0}/month/{1}{2:D2}.html", cityCode, year, month);
	//獲取該連結的原始碼
	var docText = HtmlHelper.GetWebClient(url);
	//載入原始碼,獲取頁面結構物件
	var doc = new HtmlDocument(); doc.LoadHtml(docText);
	//更加Xpath獲取表格物件
	var res = doc.DocumentNode.SelectSingleNode(@"/html[1]/body[1]/div[2]/div[6]/div[1]/div[1]/table[1]");
	if (res != null)
	{
		//獲取所有行
		var list = res.SelectNodes(@"tr");
		list.RemoveAt(0);//移除第一行,是表頭
		// 遍歷每一行,獲取日期,以及天氣狀況等資訊
		foreach (var item in list)
		{
			var dd = item.SelectNodes(@"td");
			//日期 -  - 氣溫 - 風力風向
			if (dd.Count != 4) continue;
			//獲取當前行日期
			var date1 = dd[0].InnerText.Replace("\r\n", "").Replace(" ", "").Trim();  
			//獲取當前行天氣狀況
			var tq = dd[1].InnerText.Replace("\r\n", "").Replace(" ", "").Trim();
			//獲取當前行氣溫
			var qw = dd[2].InnerText.Replace("\r\n", "").Replace(" ", "").Trim();
			//獲取當前行風力風向
			var fx = dd[3].InnerText.Replace("\r\n", "").Replace(" ", "").Trim();
			//輸出
			Console.WriteLine("{0}:{1},{2},{3}", date1, tq, qw, fx);
		}
	}
}

我們呼叫大連市2011年8月的記錄:ParsePageByCityMonth("dalian",2011,8);  結果如下:

  至於其他頁面都是這個思路,先分析xpath,再獲取對應的資訊。熟悉幾次後應該會快很多的。HtmlAgilityPack裡面的方法用多了,自己用物件瀏覽器檢視一些,會一些基本的就可以解決很多問題。

  另外,很多網頁都是直接輸出json資料,對json資料的處理我寫過一篇文章,可以參考下,純手工打造的解析json:用原始方法解析複雜字串,json一定要用JsonMapper麼? 

4.資源

  我將在下一篇文章中開放這個天氣資料庫,目前正在採集,很大,很慢。敬請關注。

相關推薦

C#+HtmlAgilityPack+XPath採集資料(採集天氣資料例子)

  第一次接觸HtmlAgilityPack是在5年前,一些意外,讓我從技術部門臨時調到銷售部門,負責建立一些流程和尋找潛在客戶,最後在阿里巴巴找到了很多客戶資訊,非常全面,剛開始是手動複製到Excel,是真尼瑪的累,雖然那個時候C#還很菜,也想能不能通過程式來批量獲取(所以平時想法要多才好)。幾經周折,終於

Python爬蟲,看看我最近部落格都寫了啥,製作高逼格的資料聚合雲圖

今天一時興起,想用python爬爬自己的部落格,通過資料聚合,製作高逼格的雲圖(對詞彙出現頻率視覺上的展示),看看最近我到底寫了啥文章。 1.1 爬取文章的標題的聚合 1.2 爬取文章的摘要的聚合 1.3 爬取文章的標題+摘要的聚合 我

c語言】真正走進指標的世界——陣列與指標的關係(一)

       每天下課之後,都感覺老師上課在神仙程式設計,我們一群凡人在底下面無表情地走神,前一秒還是在講加減乘除的基本用法,後一秒就變成了指標陣列、陣列指標、結構體指標和N級指標的性質以及運用............(真是令人頭禿 —^—) ——————

c語言】真正走進指標的世界——那些一不小心就會出現的BUG

                                    Let's     &nbs

c語言】真正走進指標的世界——指標的特性

         當你看到這篇文章時,請忘掉你之前對指標的所有認知,什麼地址什麼的統統忘掉。                      

免費體驗阿里巴巴旗艦大資料計算產品MaxCompute

什麼是MaxCompute? 眾所周知,MaxCompute是阿里雲推出的承載EB級的資料儲存能力,百PB級的單日計算能力,公共雲覆蓋國內外十幾個國家和地區,專有云包含城市大腦在內部署超過100+套的阿里巴巴的統一計算平臺。官方地址:https://www.aliyun.com/product/odps​

【工業大資料】一文讀懂《工業大資料白皮書》

來源:工信部、工業網際網路城市物聯網智庫 整理髮布轉載請註明來源和出處------   【導讀】

2019小白如何學習大資料,資深技術大咖輕鬆入門並掌握大資料

什麼是大資料? 其實大資料並不是一種概念,而是一種方法論。簡單來說,就是通過分析和挖掘全量的非抽樣的資料輔助決策。大資料可以實現的應用可以概括為兩個方向,一個是精準化定製,第二個是預測。比如像通過搜尋引擎搜尋同樣的內容,每個人的結果卻是大不相同的。再比如精準營銷、百度的推廣、淘寶的喜歡推薦,或者

一篇文章弄懂BI和大資料

BI(Business Intelligence),中文翻譯是商務智慧,是一套完整的解決方案,用來將組織中現有的資料進行有效的整合,快速準確的提供報表並提出決策依據,幫助組織做出明智的業務經營決策。 商業智慧能夠輔助的業務經營決策,既可以是操作層的,也可以是戰術層和戰略層的決策。為了將

跟阿里大牛撈乾貨:2019年玩轉人工智慧、大資料

導讀:2019年,你都立了哪些flag?等一年之後回頭看看,這些flag都能拔掉嗎?其實新的一年已經過去一週多了,這一週你是怎樣過的,有沒有一點小小的進步?   為了讓你的2019年過得充實,不虛度,華章計算機小編今天推薦10本書,作者來自於阿里的技術大牛,內容都是跟當前持續火爆的大資料行業相關

玩轉太坊智慧合約的"Hello World"

1.學習目標 瞭解智慧合約 簡單環境搭建 能夠利用solidity編寫Hello World合約 合約部署 和合約互動 2.使用solidity語言撰寫智慧合約 Ethereum上的智慧合約需要使用solidity語言來撰寫。solidity是一

25行程式碼爬取4399小遊戲資料,看下童年的遊戲是否還在

前言 本文的文字及圖片來源於網路,僅供學習、交流使用,不具有任何商業用途,如有問題請及時聯絡我們以作處理。 還記得童年的網頁小遊戲嗎?今天帶大家爬取4399小遊戲網站的資料,遊戲名字+連結地址 目標網站 http://www.4399.com/   基本環境配置 python 3.6 pych

一步一步教PowerBI利用爬蟲獲取天氣資料分析

  對於爬蟲大家應該不會陌生,我們首先來看一下爬蟲的定義:網路爬蟲是一種自動獲取網頁內容的程式,是搜尋引擎的重要組成部分。網路爬蟲為搜尋引擎從全球資訊網下載網頁,自動獲取網頁內容的應用程式。看到定義我們應該已經知道它是可以從全球資訊網上下載網頁解析網頁資料的。大家想一下在資料分析情景中它的應用場景有哪些?採集

spring boot 整合redis 一個熱門房產例子

1.新增redis依賴 就是jedis redis.clients jedis 2.9.0 2.每次點選房屋詳情熱度加一 呼叫此方法 recommandService.increase(id);//每次點選房屋熱度加1 3.recommandService如何寫主要

Spring boot(20) Spring /Spring boot使用AOP、強制使用cglib(記錄方法耗時例子

1. Spring boot 1.1 Spring boot預設使用了AOP和動態代理 RPC,AOP都會用到代理,代理的技術有jdk的Proxy代理(必須傳入介面),cglib(可以是類而非介面, spring),Javassist(jboss )而S

Mxnet:全連線層例子自定義新的操作(層)

在使用深度學習平臺時,光會使用其中已定義好的操作有時候是滿足不了實際使用的,一般需要我們自己定義新的操作。但是,絕大多數深度平臺都是編譯好的,很難再次編寫。本文以Mxnet為例,官方給出四種定義新操作的方法, 分別呼叫: 1、mx.operator.CustomOp 2、m

如何使用github(國內碼云例子)

這裡以國內碼云為例子,國內訪問github速度慢,同時碼雲沒有限制免費,功能也是十分強大,在這裡給國人贊一下,自強不息。 第一步,登入https://gitee.com/建立一個碼雲賬戶,點選到個人主頁,點選左下方紅色區域的“+”,新增專案。 第二步,新建一個新的專案

看懂大資料採集引擎之Flume&採集目錄中的日誌

歡迎關注大資料和人工智慧技術文章釋出的微信公眾號:清研學堂,在這裡你可以學到夜白(作者筆名)精心整理的筆記,讓我們每天進步一點點,讓優秀成為一種習慣! 帶你看懂大資料採集引擎之Flume&採集目錄中的日誌 一、Flume的介紹: Flume由Clo

3分鐘了解PowerShell發展歷程——PowerShell各版本資料整理

msdn 發展 mona ack html 工作 lease int -1 本文帶你了解PowerShell發展歷程,順便整理了一點資料,方便大家查詢。 Windows PowerShell? 是基於任務的命令行管理程序和腳本語言,專為進行系統管理而設計。 在 .NET F

一起學習C語言語法

作用域 鏈接 指向 nbsp itl switch語句 一個 字符串 單鏈表 《帶你學C帶你飛》第一季講解內容:C語言語法,我們會講變量、數組、函數、指針、結構、標準庫這樣一些純粹的C語言知識。 基本上你大學第一學期學的就是咱第一季的內容,我知道很多朋友學完C語言一時感覺沒