严格意义来说,采集器和爬虫不是一回事:采集器是对特定结构的数据来源进行解析、结构化,将所需的数据从中提取出来;而爬虫的主要目标更多的是页面里的链接和页面的TITLE。

采集器也写过不少了,随便写一点经验吧,算是给自己的一个备忘。

首先是最简单的:静态页面采集器。即所采集的数据来源页面是静态的,至少采集器所关心的那部分数据是静态的,可以通过直接访问页面URL的方式获取到包含目标数据的全部页面代码。这种采集器是最为常用,也是最为基础的。目前已经有很多成熟的商业化的采集器产品,不过对我来说感觉用着有些过于复杂。一些我自己编写采集器时会注意的问题在这些产品上似乎没有,或者名字不是我拟的那个,找不到。用了几次,干脆不如自己写了,还更省时间效率更高。

准备知识:HTTP协议基础、HTML语言基础、正则表达式和任意支持正则表达式的编程工具(.net、java、php、Python、ruby等等都可以)

首先第一步,是下载目标页面HTML。

这一步并没有什么太难的,.net里有HttpWebRequest和HttpWebResponse等类专门处理,其他语言里也有类似的东西。不过需要注意的是,为采集器编写下载器的时候,参数配置一定要灵活:User-Agent、Refer、Cookie等字段都得做成可配,还得支持使用代理服务器,这是为了突破目标服务器的访问限制策略或机器人识别策略。有关常见的反机器人以及反“反机器人”等相关技术会在后续文章里专门编写。

页面代码下载到本地之后,就得开始对其进行解析。有两种解析方法

1、将其当做HTML解析

熟悉HTML的人可以将下载到的HTML页面直接当做HTML来解析,这样做也是最快和最有效率的。遍历HTML元素和属性之后,直接找到关注部分数据内容,通过访问其元素、元素属性和子元素的方式获取数据。.net里原生没有HTML解析库,可以找第三方库,大多数比较好用,至少当一般拿来解析个页面提个数据之类的够用了。唯一需要注意的是需要考虑页面代码下载不完全或者目标页面结构存在错误的情况。

2、将其当做字符串,用正则表达式解析

正则表达式的好处就是灵活,在方法1失效或者实现麻烦(比如目标数据的HTML元素路径可能不固定)的时候可以考虑。使用正则表达式的思路就是寻找目标数据及其上下文的特征或者特征串,然后编写正则表达式将其匹配提取出来即可。

以下以解析bing的搜索结果页为例,介绍静态采集器工作的基本原理。

首先是页面获取。点击两下就能发现页面参数的规律,举例:

http://cn.bing.com/search?q=MOLLE+II&first=31

这个URL代表以“MOLLE”“II”两个关键词搜索,当前页面是是第四页。FIRST参数指的是本页第一个显示的搜索结果的索引号,第四页显示31-40个搜索结果。

这是用GET方式传递参数,大多数情况下都是这样的。如果目标页面用POST方式传递参数,用浏览器的开发者模式抓个包看看参数是啥就OK了。

然后我们就下载到了目标页面,将其在正则表达式测试器里打开:

恩,这活儿干得多了干脆自己写了一个趁手的工具。

我们的目标是提取到搜索结果里的链接文字和链接URL。对于需要从同一个页面解析得到两项或者多项相互对应的数量一样的数据,也有两种策略:根据这些数据不同的特征直接编写表达式从页面里提取目标数据(比如先用一个正则处理页面,拿到所有的链接标题文字,再用一个正则处理页面,拿到所有的链接URL),或者分析页面结构,找到包含目标数据项的最小页面结构(比如html表格里的表格行<tr>元素),再进行解析。其中后者更靠谱一点,也可以省去很多干扰,但稍微麻烦一些。以下以后一种方式进行介绍。

用浏览器的检查工具(Chrome里以前叫查看元素,新版改叫检查了,刚刚还找了半天)分析页面代码,我们可以发现所有的搜索内容都包含在一个id属性为"b_results"的<ol>标签里。编写表达式对其进行提取:

对于解析HTML用到的正则,零宽断言和逆序环视(查找)是经常用到的,用于提取带有特定前缀和后缀的字符串。有关正则表达式的技术博客园已经有很多相关文章,这里不再赘述。

不过需要注意的是,对于.net的正则表达式库,有一些开关需要注意。对于解析html的时候,经常需要将SingleLine参数选中,这样引擎会把字符串里所有的回车当成普通字符,而不是当成一行数据的结尾。不过这也并非绝对,也需要根据实际情况进行灵活配置。

另外还有一个小技巧。在移动端盛行的今天,一些网站会根据用户浏览器请求里的USER-AGENT提供不同的页面,对手机端发起的请求就会提供手机版的页面,出于节省客户流量的考虑,一般手机版的页面会比PC端的干净一些,页面噪音更少。

继续回到页面解析,刚刚已经找到包含所有目标元素的页面结构,实际上如果发现目标数据的最小结构的特征在页面里也是唯一的,直接提取也无妨:

这样我们就拿到了所有包含目标数据的<li>标签的内容。顺带一提,因为截图里工具使用的NOKIA手机的USER AGENT,所以我拿到的是手机版的页面,和PC版略有不同,更干净一点。

下一步我们对每个元素进行解析。由于所有li标签的格式结构都是一样的,我们可以用同一套正则解析。

我们的目标是链接标题和链接URL,说白了,就是<a>标签的href属性和标签内容。

直接写表达式就好:

然后对于每个li标签的内容使用同样的表达式进行处理就OK了。

好了,采集器的基本原理介绍完毕,我自己写的这个正则工具可以我博客里找到,各位使用愉快,欢迎报BUG和功能建议。

下一篇将会介绍一下动态页面数据获取。

WEB页面采集器编写经验之一:静态页面采集器的更多相关文章

  1. 浅谈php生成静态页面

    一.引 言 在速度上,静态页面要比动态页面的比方php快很多,这是毫无疑问的,但是由于静态页面的灵活性较差,如果不借助数据库或其他的设备保存相关信息的话,整体的管理上比较繁琐,比方修改编辑.比方阅读权 ...

  2. PHP生成静态页面详解

    PHP生成静态页面详解 看到很多朋友在各个地方发帖问PHP生成静态文章系统的方法,以前曾做过这样一个系统,遂谈些看法,以供各位参考.好了,我们先回顾一些基本的概念. 一,PHP脚本与动态页面. PHP ...

  3. ASP.Net MVC如何访问的静态页面

    MVC开发中,因为View文件夹下的web.config文件默认会把任何方法的请求的任何文件,路径都交给 System.Web.HttpNotFoundHandler 去处理.起到Controller ...

  4. SpringMVC与SpringBoot返回静态页面遇到的问题

    1.SpringMVC静态页面响应 package com.sv.controller; import org.springframework.stereotype.Controller; impor ...

  5. 用 Smarty 生成静态页面入门介绍

    why Smarty? 随着公司首页(以下简称首页)流量越来越大,最近开始考虑使用后台语言生成静态页面的技术. 我们知道,一个简单页面一般是一个 .html(或者 .htm ..shtml)后缀的文件 ...

  6. Ruby on Rails Tutorial 第三章 静态页面

    1.生成静态页面 $ rails generate controller StaticPages home help    #生成主页和帮助页面的路由.控制器及静态页面 $ rails destroy ...

  7. Java项目生成静态页面

    第一次做项目需要生成静态页面,网上很多大牛对将网页生成静态页面有很多异议.说一下我的看法. 不外乎有以下因素: 1.从页面加载时间来看:静态页面不需要与数据库建立连接,尤其是访问数据量较大的页面,这种 ...

  8. 使用 gulp-file-include 构建前端静态页面

    前言 虽然现在单页面很流行,但是在 PC 端多页面还是常态,所以构建静态页面的工具还有用武之地.最近也看到了一些询问如何 include HTML 文件的问题. 很多时候我们在写静态页面的时候也希望能 ...

  9. HTML:调用静态页面html 的几种方法

    今天做办公用品管理系统时,发现需要用到在一个静态页面html 中调用多个静态页面html的内容.查找资料总结了以下一些方法: 一.iframe引入的方法 代码如下: <!-- 部门--> ...

随机推荐

  1. HTTP、FTP状态码 (share)

    来源:http://www.cnblogs.com/setsail/archive/2012/03/23/2413577.html HTTP1xx - 信息提示(这些状态代码表示临时的响应.客户端在收 ...

  2. 用bugzilla统计BUG

    bugzilla—— reports—— Tabular reports—— 选择版本号啥的跟search一样 上面的行标Vertical Axis选Resolution:列标Horizontal A ...

  3. git .gitignore

    github 搜索 .gitignore 外层为语言使用的,里层为编译器使用的,分别添加到自己的文件中. 目前Androidstudio使用gradle作为项目管理,.idea   .iml  文件都 ...

  4. 启动struts2项目出现classnotfound错误

    由于工作需求.需要了解struts2项目,前几天部署了一个struts2的demo,研究url的解析过程,昨天还是好好的,今天修改了一下web.xml文件,然后启动Tomcat就报错,错误如下: 严重 ...

  5. jQuery下通过$.browser来判断浏览器

    使用方法: $.browser.['浏览器关键字'] 代码如下: $(function() { if($.browser.msie) { alert("this is msie") ...

  6. bootstrap学习

    1. bootstrap使用了less作为预编译器,他是结构清晰层次分明的css页面构建样式,即使你不喜欢bootstrap的样式,你仍然可以借鉴bootstrap编写css的这种方式 2.boots ...

  7. Python底层socket库

    Python底层socket库将Unix关于网络通信的系统调用对象化处理,是底层函数的高级封装,socket()函数返回一个套接字,它的方法实现了各种套接字系统调用.read与write与Python ...

  8. 线程安全及Python中的GIL

    线程安全及Python中的GIL 本博客所有内容采用 Creative Commons Licenses 许可使用. 引用本内容时,请保留 朱涛, 出处 ,并且 非商业 . 点击 订阅 来订阅本博客. ...

  9. css预处理语言的模块化实践

    编写css是前端工作中,一项普通而又频繁的劳动,由于css并不是一门语言,所以在程序设计上显得有些简陋.对于小型项目来说,css的量还不至于庞大,问题没有凸显,而如果要开发和持续维护一个较为大型的项目 ...

  10. js实现页面局部弹窗打印

    原文出自:http://www.haorooms.com/post/css3media 在网页中经常看到有打印功能,点击之后,只针对特定区域进行的打印.网上看了一下,大体上有2中实现方法,一种是用cs ...