C#+HtmlAgilityPack+XPath带你采集数据(以采集天气数据为例子)

  第一次接触HtmlAgilityPack是在5年前,一些意外,让我从技术部门临时调到销售部门,负责创建一些流程和寻找潜在客户,最后在阿里巴巴找到了不少客户信息,很是全面,刚开始是手动复制到Excel,是真尼玛的累,虽然那个时候C#还很菜,也想能不能经过程序来批量获取(因此平时想法要多才好)。几经周折,终于发现了HtmlAgilityPack神器,这几年也用HtmlAgilityPack采集了不少类型数据,特别是足球赛事资料库的数据采集以及天气数据采集,都是使用HtmlAgilityPack,因此把本身的使用过程总结下来,分享给你们,让更多人接触和学会使用,给本身的工做带来遍历。node

  今天的主要内容是HtmlAgilityPack的基本介绍、使用,实际代码。最后咱们以采集天气数据为例子,来介绍实际的采集分析过程和简单的代码。咱们将在下一篇文章中开源该天气数据库和C#操做代码。采集核心就只是在这里介绍,其实核心代码都有了,本身加工下就能够了,同时也免费对有须要的人开放。至于具体详情,请关注下一篇文章。 数据库

.NET开源目录:【目录】本博客其余.NET开源项目文章目录 json

本文原文地址:C#+HtmlAgilityPack+XPath带你采集数据(以采集天气数据为例子)  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的相关表达也很基础,基本足够用了。app

复制代码
<?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标签,就是咱们要采集的行了。下面咱们用代码来获取上述结构。先看看获取页面源代码的代码:

1
2
3
4
5
6
7
8
9
10
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;
}

   下面是分析每一个省份下属县市区的程序,限于篇幅咱们省掉了数据库部分,只采集城市和拼音代码,并输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/// <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,而后一次获取每行,每列,进行对应便可,看代码,都进行了详细的注释:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/// <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.资源

HTML解析利器HtmlAgilityPack

HtmlAgilityPack 之 HtmlNode类

网易新闻页面信息抓取 -- htmlagilitypack搭配scrapysharp

C#相似Jquery的html解析类HtmlAgilityPack基础类介绍及运用

我把分析HAPExplorer 工具共享一些吧,这里下载:HtmlAgilityPack分析工具.rar

  我将在下一篇文章中开放这个天气数据库,目前正在采集,很大,很慢。敬请关注。

转自:https://www.cnblogs.com/asxinyu/p/CSharp_HtmlAgilityPack_XPath_Weather_Data.html

相关文章
相关标签/搜索