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

获取目标网页的信息很简单,使用网络编程,利用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. C#自动更新本地程序

    关于系统的自动更新.近日有一情况是需要将java端后台最新版本的系统文件覆盖本地客户端,简称自动更新了. 本地会获取当前系统的版本号去请求后台java的接口数据.返回给我的是后台压缩包转的base64 ...

  2. 物流管理系统(数据库+后台+springMVC+Mybatis+layui)

    数据库:mysql create database WBG_logistics; use WBG_logistics; #1管理员表 create table admin( a_id int prim ...

  3. C# foreach语句

    一.C# foreach语句 foreach语句能够对实现Ienumerable接口的容器进行遍历,并提供一个枚举器来实现Ienumerable接口.foreach语句为数组或对象集合中的各个元素执行 ...

  4. React后台管理系统-订单管理

    1.订单管理页面和商品管理页面类似,都是一个搜索组件+列表组件 2.搜索框search组件 import React from 'react';   class ListSearch extends ...

  5. ES6初识-解构赋值

    数组解构赋值 [a,b]=[1,2]; . 方法返回 function f(){ return [1,2] } let a,b; [a,b]=f();//a=1,b=2   function f1() ...

  6. leetcode笔记(二)94. Binary Tree Inorder Traversal

    题目描述 (原题目链接) Given a binary tree, return the inorder traversal of its nodes' values. For example:Giv ...

  7. SAP库存历史库存表更新逻辑 (转)

    根据库存类型的不同,库存信息保存在不同的表中,具体而言见下表 库存类型 当前库存 历史库存 库存金额 历史库存金额 工厂级别库存 MARC MARCH MBEW MBEWH MBEW 库存地点库存 M ...

  8. DNS介绍与安装使用

    DNS简介 DNS是互联网的一项服务.它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网.DNS使用TCP和UDP的53号端口. DNS服务的基本概念 在使用DNS前需要了解 ...

  9. linux环境下安装 openOffice 并启动服务

    一.背景故事 这两天遇到一个大坑,客户要做office 文档在线预览功能,于是乎就要把office文档转换成pdf交给前端显示.      在某度找了一圈都说openOffice+jodconvert ...

  10. 【机器学习算法基础+实战系列】SVM

    概述 支持向量机是一种二分类模型,间隔最大使它有别于感知机.支持向量机学习方法由简至繁的模型:线性可分支持向量机(linear support vector machine in linearly s ...