做开发的,可能都做过信息采集相关的程序,史林枫也经常做一些数据采集或某些网站的业务办理自动化操作软件。

获取目标网页的信息很简单,使用网络编程,利用HttpWebResponse、HttpWebRequest和WebClient就可以了。

复杂的是获取网页内容后,需要对关键信息进行过滤,最初史林枫主要使用正则表达式来匹配目标数据。

这样的匹配也能达到目的,但对于不熟悉正则表达式的开发者或初学者就比较吃力了,尤其是比较复杂的正则。

最好要有专门的工具先测试,再把正则放到程序中测试。这里推荐RegexTester.exe。

后来,一次偶然的机会接触到HtmlAgilityPack。这是个开源的类库。想研究源码的可以移步这里:HtmlAgilityPack源码

刚开始使用是比较随性的,需要用了就开始new 然后找跟节点,找目标节点,取属性或取文本。使用的多了,就有封装类库的想法,然后在使用过程中不断改进,更新,目前使用还是比较稳定的。

使用的时候需要引用HtmlAgilityPack.dll  Visual Studio中的NuGet可以获取到

先上类库源码:

 /// <summary>
/// html文档解析辅助类库
/// </summary>
public class HtmlParse {
private readonly HtmlDocument doc = new HtmlDocument(); /// <summary>
/// 构造函数 初始化文档并解析 默认utf-8模式
/// </summary>
/// <param name="htmlOrUrl">获取的html字符串或url链接</param>
public HtmlParse(string htmlOrUrl) {
InitDoc(htmlOrUrl);
} /// <summary>
/// 构造函数 初始化文档并解析 默认utf-8模式
/// </summary>
/// <param name="htmlOrUrl">获取的html字符串或url链接</param>
/// <param name="encode">字符编码</param>
public HtmlParse(string htmlOrUrl, string encode) {
InitDoc(htmlOrUrl, encode);
} /// <summary>
/// 根据url或html字符串获取文档并解析
/// </summary>
/// <param name="htmlOrUrl">html字符串或url</param>
/// <param name="encode">网站编码</param>
/// <returns></returns>
public HtmlDocument InitDoc(string htmlOrUrl, string encode = "utf-8") {
if (htmlOrUrl.Trim().StartsWith("http")) {
htmlOrUrl = NetHelper.GetPageStr(htmlOrUrl, "", encode);
}
doc.LoadHtml(htmlOrUrl);
return doc;
} /// <summary>
/// 获取节点集合
/// </summary>
/// <param name="xPath"></param>
/// <returns></returns>
public HtmlNodeCollection GetNodes(string xPath) {
return doc.DocumentNode.SelectNodes(xPath);
} /// <summary>
/// 获取单个节点
/// </summary>
/// <param name="xPath"></param>
/// <returns></returns>
public HtmlNode GetNode(string xPath) {
return doc.DocumentNode.SelectSingleNode(xPath);
} /// <summary>
/// 获取节点的属性值
/// </summary>
/// <param name="node">节点</param>
/// <param name="attrName">属性名称</param>
/// <returns></returns>
public string GetNodeAttr(HtmlNode node, string attrName) {
if (node == null || node.Attributes[attrName] == null) {
return string.Empty;
}
return node.Attributes[attrName].Value;
} /// <summary>
/// 获取节点的InnerText的值
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
public string GetNodeText(HtmlNode node) {
if (node == null) {
return string.Empty;
}
return node.InnerText;
} /// <summary>
/// 获取节点的InnerHtml或OuterHtml值
/// </summary>
/// <param name="node">节点</param>
/// <param name="isOuter">是否要获取OuterHtml</param>
/// <returns></returns>
public string GetNodeHtml(HtmlNode node, bool isOuter = false) {
if (node == null) {
return string.Empty;
}
if (isOuter) {
return node.OuterHtml;
}
return node.InnerHtml;
} /// <summary>
/// 根据Xpath和属性名称获取属性值
/// </summary>
/// <param name="xPath"></param>
/// <param name="attrName"></param>
/// <returns></returns>
public string GetNodeAttr(string xPath, string attrName) {
var node = GetNode(xPath);
return GetNodeAttr(node, attrName);
} /// <summary>
/// 根据XPath获取节点的InnerText
/// </summary>
/// <param name="xPath"></param>
/// <returns></returns>
public string GetNodeText(string xPath) {
var node = GetNode(xPath);
return GetNodeText(node);
} /// <summary>
/// 根据XPath获取节点的InnerHtml或OuterHtml值
/// </summary>
/// <param name="xPath"></param>
/// <param name="isOuter"></param>
/// <returns></returns>
public string GetNodeHtml(string xPath, bool isOuter = false) {
var node = GetNode(xPath);
return GetNodeHtml(node);
}
}

提示:想要熟练的使用HtmlAgilityPack,必须要了解XPath的相关知识。不懂的可以移步这里:XPath入门教程

实际上XPath主要注意几个要点就可以解决80%的问题。

1.以/开头的是从根节点开始选取,以//开头的是模糊选取,而不考虑它们的位置

2.可以使用属性来定位要选取的节点或节点集合 比如//span[@class="time"] 就是选择文档中所有class="time"的span元素。

3.节点集合中的某一个使用[i]的方式选取 比如 //span[@class="time"][1] 就是选择文档中所有class="time"的span元素中的第一个span。注意在这里选择节点的索引是从1开始的,而不是0

4.使用|  来做容错选择,比如一个网页中某个数据可能在<div class="a1"></div>中 也可能在<div class="a2"></div> 这时就可以用 //div[@class="a1"]|//div[@class="a2"] 作为XPath

5.XPath中需要用到的引号 可以使用单引号  因为C#中字符串需要用双引号,XPath中需要引号的使用单引号即可,这样不用转义了。

上面还用到了一个NetHelper。主要用于获取Url的内容。这东西网上一大堆,这里就不献丑了。自行结合即可。

使用方法也很简单:

// 比如这里获取我的博客首页内容 并解析当前文章列表
var doc = new HtmlParse("http://www.cnblogs.com/jayshsoft/");
var nodeList = doc.GetNodes("//div[@class='post post-list-item']");
foreach (var node in nodeList) {
//这里写自己的逻辑
}

自从封装好类库后,采集内容就变得非常Easy了,只要把流程分析好即可,Html文章中的元素任你宰割,蹂躏。。。

另外,推荐一个FireFox浏览器插件:XPath Checker

有了它 你就可以在浏览器中直接写好XPath,直接看到结果 一目了然

直接上图

右键点击网页空白处 选择View XPath

输入XPath 就可以得到你想要的数据了。是不是很直观?是就推荐一下  嘿嘿。。。

史林枫:开源HtmlAgilityPack公共小类库封装 - 网页采集(爬虫)辅助解析利器【附源码+可视化工具推荐】的更多相关文章

  1. Python的开源人脸识别库:离线识别率高达99.38%(附源码)

    Python的开源人脸识别库:离线识别率高达99.38%(附源码) 转https://cloud.tencent.com/developer/article/1359073   11.11 智慧上云 ...

  2. 微信小程序版博客——开发汇总总结(附源码)

    花了点时间陆陆续续,拼拼凑凑将我的小程序版博客搭建完了,这里做个简单的分享和总结. 整体效果 对于博客来说功能页面不是很多,且有些限制于后端服务(基于ghost博客提供的服务),相关样式可以参考截图或 ...

  3. Java豆瓣电影爬虫——小爬虫成长记(附源码)

    以前也用过爬虫,比如使用nutch爬取指定种子,基于爬到的数据做搜索,还大致看过一些源码.当然,nutch对于爬虫考虑的是十分全面和细致的.每当看到屏幕上唰唰过去的爬取到的网页信息以及处理信息的时候, ...

  4. 开源方案搭建可离线的精美矢量切片地图服务-8.mapbox 之sprite大图图标文件生成(附源码)

    项目成果展示(所有项目文件都在阿里云的共享云虚拟主机上,访问地图可以会有点慢,请多多包涵). 01:中国地图:http://test.sharegis.cn/mapbox/html/3china.ht ...

  5. C#轻量级通通讯组件StriveEngine —— C/S通信开源demo(2) —— 使用二进制协议 (附源码)

    前段时间,有几个研究ESFramework通信框架的朋友对我说,ESFramework有点庞大,对于他们目前的项目来说有点“杀鸡用牛刀”的意思,因为他们的项目不需要文件传送.不需要P2P.不存在好友关 ...

  6. 微信小程序之蓝牙开发(详细读数据、写数据、附源码)

    本文将详细介绍微信小程序的蓝牙开发流程(附源码)准备:微信只支持低功耗蓝牙也就是蓝牙4.0,普通的蓝牙模块是用不了的,一定要注意. 蓝牙可以连TTL接到电脑上,再用XCOM调试 一开始定义的变量 va ...

  7. 日志组件Log2Net的介绍和使用(附源码开源地址)

    Log2Net是一个用于收集日志到数据库或文件的组件,支持.NET和.NetCore平台. 此组件自动收集系统的运行日志(服务器运行情况.在线人数等).异常日志.程序员还可以添加自定义日志. 该组件支 ...

  8. 自制小工具大大加速MySQL SQL语句优化(附源码)

    引言 优化SQL,是DBA常见的工作之一.如何高效.快速地优化一条语句,是每个DBA经常要面对的一个问题.在日常的优化工作中,我发现有很多操作是在优化过程中必不可少的步骤.然而这些步骤重复性的执行,又 ...

  9. JS小游戏:贪吃蛇(附源码)

    javascript小游戏:贪吃蛇 此小游戏采用的是面向对象的思想,将蛇,食物,和游戏引擎分为3个对象来写的. 为方便下载,我把js写在了html中, 源码中暂时没有注释,等有空我在添加点注释吧. 游 ...

随机推荐

  1. MyBatis中解决字段名与实体类属性名不相同的冲突

    一: 通过在查询的sql语句中定义字段名的别名,让字段名的别名和实体类的属性名一致,这样就可以表的字段名和实体类的属性名一一对应上了,这种方式是通过在sql语句中定义别名来解决字段名和属性名的映射关系 ...

  2. 配置SSIS 包部署

    包配置是干嘛滴! 使用包配置可以从开发环境的外部设置运行时属性和变量.         把用户变量转换成Config文件 步骤: 准备工作 把第一个例子中的userinfo.txt复制两份,放到同一个 ...

  3. JAVA通用BaseServlet的产生和代码实现

    BaseServlet的作用: 我们先写一个工具类:BaseServlet. 我们知道,写一个项目可能会出现N多个Servlet,而且一般一个Servlet只有一个方法(doGet或doPost),如 ...

  4. Pop–实现任意iOS对象的任意属性的动态变化

    简介 Pop 是一个可扩展的动画引擎,可用于实现任意iOS对象的任意属性的动态变化,支持一般动画,弹性动画和渐变动画三种类型. 项目主页: pop 最新示例: 点击下载 注意: 官方代码中,并不包含实 ...

  5. VCTransitionsLibrary –自定义iOS交互式转场动画的库

    简介 VCTransitionsLibrary 提供了许多适用于入栈,出栈,模态等场景下控制器切换时的转场动画.它本身提供了一个定义好的转场动画库,你可以拖到自己工程中直接使用;也提供了许多拥有不同转 ...

  6. 深入理解 SVG 系列(一) —— SVG 基础

    来源:https://segmentfault.com/a/1190000015652209 本系列文章分为三个部分: 第一部分是 SVG 基础. 主要讲 SVG 的一些基础知识,包括 SVG 基本元 ...

  7. 在win10上同时安装Python2/Python3

    如何在win10上同时安装python2和python3? 为了满足日常工作或者学习的需要,我们可能会经常用到python2和python3,下面是给大家在win10上同时安装两个版本的python的 ...

  8. scrapy--boss直聘

    Hi,大家好.有段时间没来更新scrapy爬取实例信息了,前2天同事说爬取拉勾,boss直聘等网站信息比较困难.昨天下午开始着手爬取boss直聘内Python爬虫的信息,比想象中的简单很多. 需要解决 ...

  9. python__基础 : 类的继承,调用父类的属性和方法

    1.继承,调用父类属性方法 在python里面,继承一个类只需要这样写: class Animal: def heshui(self): print('动物正在喝水') class Cat(Anima ...

  10. Python基础-字符串的使用

    基础知识 字符串解释:字符串是不可变的,所有元素赋值和切片赋值操作都是非法的,属于序列一种(字符串.元组.列表). 一.格式化字符串 (1).format()方法==str.format() 作用:将 ...