《搜索引擎零距离》第二章 智能网络爬虫 (1)
roki
2009-06-16
本章将主要介绍“智能网络爬虫系统”的主要功能与特点,通过一个完整的系统实例来展示垂直搜索引擎的基石——“结构化信息采集与分析系统”的主要业务逻辑与实现思想。为了能够方便地表达结构化信息采集与分析的各种业务需求,本书中引入了一种表达式和一个脚本语言,分别叫做IEE表达式和IRS脚本语言。
2.1 智能网络爬虫的定义与特点 本书中定义的智能网络爬虫是指这样一个系统:可以按照人工指定的规则来遍历互联网上的页面,并按照特定格式的表达式的要求,从页面中提取结构化信息,然后按照一定的方式组织这些信息,并存放进数据库。本章的主要内容是描述这样一个智能网络爬虫需要具备的业务功能。 2.2 抓取入口定义 抓取入口是指爬虫的抓取工作的起始页面,假设我们需要抓取一个小说网站上的页面信息,我们可以用如下方式来指定爬虫的入口: ------------------------------------------------------------------- 入口 ' http://33wap.net/wap/fenlei.asp' 配置:编码=UTF-8,JS=否. ------------------------------------------------------------------- 其中,“配置:编码=UTF-8, JS=否.”这句的意思是,用UTF-8 编码来读取页面内容,并且不需要在分析页面的时候启用JavaScript解析引擎。 附注:http://33wap.net/wap/fenlei.asp是一个WML页面,需要用支持WML的浏览器,比如Opera来打开。 2.3 次级页面自动发现 次级页面是指抓取并分析一个页面(比如小说列表页)之后,由于需要进入下一级的页面(比如小说详细信息页)去采集更多的信息,因此智能爬虫需要从本级的页面中分析出下一级页面的URL地址,然后进入这个页面。这样一种从一个页面进入另一个页面的爬虫行为,称为“进入次级页面”。 以上一节中的入口地址为例子, 这个页面上的主要内容如下: =书城分类= <a href="list.asp?id=1&sb=123456789">魔法玄幻</a> <a href="list.asp?id=2&sb=123456789">武侠仙侠 </a> <a href="list.asp?id=3&sb=123456789">浪漫言情 </a> <a href="list.asp?id=4&sb=123456789">现代都市 </a> <a href="list.asp?id=5&sb=123456789">历史史记 </a> <a href="list.asp?id=6&sb=123456789">军事天地 </a> <a href="list.asp?id=7&sb=123456789">游戏世界 </a> <a href="list.asp?id=8&sb=123456789">体育竞技 </a> <a href="list.asp?id=9&sb=123456789">科学幻想 </a> <a href="list.asp?id=10&sb=123456789">灵异鬼怪 </a> <a href="list.asp?id=11&sb=123456789">诗词美文 </a> <a href="list.asp?id=12&sb=123456789">同人系列 </a> <a href="list.asp?id=13&sb=123456789">原创剧本 </a> <a href="list.asp?id=14&sb=123456789">生活励志 </a> <a href="list.asp?id=16&sb=123456789">文学名著</a> 现在,我们希望爬虫进入各个分类页面,继续采集更详细的信息。为了表达这样的需求,可以这样编写IEE表达式: ------------------------------------------------------------------- 匹配 '<a href="list.asp?id=[$]&sb=[$]">[$category]</a>' '%novelList ' 次级页面 '%novelList' '小说列表页' ------------------------------------------------------------------- 上述IEE表达式表述了如下需求: (1) 匹配页面中符合 <a href="list.asp?id=.*?&sb=.*?">(.*?)</a> 这个模式的内容(系统会把[$varName]转换为(.*?)正则表达式,把[$]转换为.*?)。 (2) 把在模式中(.*?)这个位置匹配到的内容存进变量$category(比如“魔法玄幻”)。 (3) 从整个匹配到的内容中的链接存放到变量%novelList(比如list.asp?id= 1&sb=123456789)。 (4) 进入各个%novelList中存储的地址。 假设“小说列表页”的页面内容如下: ------------------------------------------------------------------- 01.历史 <a href="http://book.17wap.com/bookshow.aspx?bookid =9991175126624052">《乱隋唐》</a> 02.军事<a href=" http://book.17wap.com/bookshow.aspx?bookid= 9991175126625671">《异界二战》</a> 03.玄幻<a href=" http://book.17wap.com/bookshow.aspx?bookid= 9991175126611369">《火影同人WhiteSnow》</a> 04.玄幻 <a href=" http://book.17wap.com/bookshow.aspx?bookid= 9991175126625735">《未来进化》</a> ------------------------------------------------------------------ 在这个页面上,为了取出书名和阅读地址,需要编写如下IEE表达式: ------------------------------------------------------------------- 匹配:'小说' '<a href="[$readUrl]">[$bookName]</a> '%bookDetail' ------------------------------------------------------------------- 这个IEE表达式能把“小说列表页”上的“阅读地址”和“书名”的列表分析出来。 如果我们只是想要书名和阅读地址,那么爬虫走到这一步就可以了,但是如果我们还想要小说的详细信息,那么还需要进入“阅读地址”页面,并进一步分析。我们在上述的IEE表达式上加上一句进入次级页面语句,变成: ------------------------------------------------------------------- 页面配置 页面名 '小说列表页' 匹配:'小说' '<a href="[$readUrl]">[$bookName]</a> '%bookDetail' 次级页面 '%bookDetail' '小说详细信息页' ; 页面配置 页面名 '小说详细信息页' 匹配:'brief' '<p>《[$bookName]》[$status]…<br>简介:[$brief] 点击' '' ; ------------------------------------------------------------------- 上述的语句是由多个IEE表达式组成的一段脚本,本书中把这种脚本命名为IRS(Info Retrival Script)。 上述的IRS脚本表述了这样的需求:从“小说列表页”中提取出小说详细页的地址列表,并提取出“阅读地址($readUrl)”,然后进入这个页面,从页面中提取出书名($bookName),状态($status),简介( $brief)。 2.4 次级页面地址拼接 存在这样一种情况:用某个IEE表达式提取到数据之后,希望用这个数据来拼接成一个新的URL地址,然后再进入这个地址采集信息。 考虑如下例子。 假设有一个歌曲列表页面内容如下: ----------------------------------------------------------- 爸妈的话(泳儿-music) 世界上最伤心的人(常艾非-music) 背叛的心(阿振-music) 下一页(1/65) ------------------------------------------------------------- 对于这个页面,我们可以用 ----------------------------------- 匹配:"page" '下一页([$startPage]/[$endPage])' ----------------------------------- 来分析出:$startPage=1, $endPage=65。我们为了进入对应的65个歌曲列表页,可以编写如下IRS脚本: ----------------------------------- 匹配:"page" '下一页([$startPage]/[$endPage])' '%mainPage' '%mainPage,#extend-> http://abc.com/songlist.jsp?page=[$startPage..$endPage]' 次级页面 '%mainPage' '音乐列表页' ----------------------------------- 上述IEE表达式中的#extend->符号后面跟的是需要扩展的地址表达式,其中 [$startPage .. $endPage]这段表达式说明当前位置将被从 $startPage到 $endPage的数字替换,也就是从1到65。于是,爬虫就可以进入 http://abc.com/songlist.jsp?page=1 http://abc.com/songlist.jsp?page=2 … http://abc.com/songlist.jsp?page=65 这些页面,来获取进一步的数据。 |
|
roki
2009-06-16
2.5 已爬地址处理
爬虫系统应该对所有处理过的URL地址都保存其状态,然后可以通过这个信息来实现以下几个功能: (1) 略过对已经处理过的URL地址的处理。 (2) 略过对未更新过的URL地址的处理。 功能解释。 假设我们在一次数据采集过程中处理了如下一个页面: http://abc.com/novellist.jsp?page=1 ------------------------------------------------------------ <a href="novel1.jsp">小说1</a> <a href="novel2.jsp">小说2</a> <a href="novel3.jsp">小说3</a> ------------------------------------------------------------- 并分别进入novel1.jsp、novel2.jsp和novel3.jsp获取了这些小说的详细信息。当我们需要重新采集一遍这个列表页上的数据时,爬虫又一次打开这个页面,发现内容更新了,变成: ------------------------------------------------------------- <a href="novel1.jsp">小说1</a> <a href="novel3.jsp">小说3</a> <a href="novel4.jsp">小说4</a> -------------------------------------------------------------- 由于novel1.jsp和novel3.jsp这两个页面在前次采集中已经处理过了,因此为了避免不必要的重复工作,我们可以忽略这两个地址,只进入novel4.jsp去获取进一步的详细信息。 这个功能就是“略过对已经处理过的URL地址的处理”。 如果我们需要检测详细信息是否有更新,比如前次访问页面时,页面内容是: http://abc.com/novel1.jsp ----------------------------------- 小说名: 诛仙 章节数:18章 ……………………… ------------------------------------ 在前次的访问中,爬虫系统访问了该页面并保存了“小说名”和“章节数”这两个信息。如果本次访问时,本页的内容变成如下: ----------------------------------- 小说名: 诛仙 章节数:20章 …………………………… ------------------------------------ 那么,说明这个页面更新过了,要重新保存一次,但是,页面如果没有更新的话,就不需再重复保存了。这个功能就是“略过对未更新过的URL地址的处理”。 为了使用以上两个功能,可以把前例中的IRS脚本改写为: ------------------------------------------------------------------- 页面配置 页面名 '小说列表页' 匹配:'小说' '<a href="[$readUrl]">[$bookName]</a> '%bookDetail' 次级页面 '%bookDetail,#处理条件=未访问过;' '小说详细信息页' ; 页面配置 页面名 '小说详细信息页' 匹配:'brief' '<p>《[$bookName]》[$status]…<br>简介:[$brief] 点击' '' ; ------------------------------------------------------------------- 上述描述中,加上了“,#处理条件=未访问过;”这一段,这就可以配置智能爬虫忽略对已经处理过的页面的访问。 2.6 信息采集强度控制 由于智能爬虫系统挖掘数据的对象主要是互联网上的Web服务器,而Web服务器能承受的压力是有限的,如果采集的强度过大,很可能导致目标Web服务器当机,但是强度太低又会导致挖掘速度过慢,因此需要对智能爬虫系统的信息采集强度进行控制。 采集强度控制主要通过两个参数的设置:“并发线程数”和“停歇时间”。“并发线程数”是指同时可以有多少个线程对一个Web网站进行信息采集,“并发线程数”越大,任务执行得越快,但是对爬虫系统和对方Web服务器的压力也越大。“停歇时间”是指一个采集线程处理完一个页面之后,停下来等多少时间之后再开始处理下一张页面的时间,“停歇时间”越短,就意味着马不停歇地访问对方服务器,虽然采集速度会加快,但是也有把对方Web服务器拖垮的危险。 IRS语言中,对这两个参数的设置提供了支持,典型的示例如下: ---------------------------------------- 爬虫配置: 最大线程数=5,抓取延迟=1000. ---------------------------------------- 其中的1000是指1000毫秒。 2.7 模拟用户登录 有些网页内容需要用户登录之后才能正常显示,因此智能爬虫系统需要能够模仿真实用户的登录行为。Web网站的登录往往是通过一个登录页面,把用户名和密码用POST请求发送到对方Web服务器来完成的,大多数情况下,只需要知道这个POST请求的目标地址,以及用户名和密码,就可以由程序自动登录,并保存登录状态了。 IRS 语言对自动登录提供了如下的支持: ---------------------------------------- 爬虫配置: 自动登录=http://abc.com/login.jsp?name=user1&passwd=mypw ---------------------------------------- 在这样的配置之下,智能爬虫在开始正式的数据采集之前,会先访问登录页面,获得页面访问权限。 2.8 验证码识别 某些情况下,在输入用户名和密码之后,还需要输入验证码才能成功登录。一些简单的验证码可以通过程序来识别。虽然验证码识别技术是一项相当困难的技术,但是智能爬虫系统应当能够识别简单的验证码。 智能爬虫系统可以通过验证码图片地址,获取图片文件,然后用一些图像识别的算法进行光学识别,比如人工神经网络算法中的BP算法、SOM算法等,开源软件领域,惠普提出了Tesseract文字识别项目,现在已经由Google赞助并开放源代码。 2.9 代理服务器设置 代理服务器英文全称是Proxy Server,其功能就是代理网络用户去取得网络信息。形象地说:它是网络信息的中转站。 在一般情况下,我们使用网络浏览器直接去连接其他Internet站点取得网络信息时,须送出Request信号来得到回答,然后对方再把信息以bit方式传送回来。代理服务器是介于浏览器和Web服务器之间的一台服务器,有了它之后,浏览器不是直接到Web服务器去取回网页而是向代理服务器发出请求,Request信号会先送到代理服务器,由代理服务器来获得浏览器所需要的信息并传送给浏览器。而且,大部分代理服务器都具有缓冲的功能,就好像一个大的Cache,它有很大的存储空间,它不断将新取得数据储存到本机的存储器上。如果浏览器所请求的数据在本机的存储器上已经存在而且是最新的,那么它就不重新从Web服务器取数据,而直接将存储器上的数据传送给用户的浏览器,这样就能显著提高浏览速度和效率。 更重要的是:Proxy Server(代理服务器)是Internet链路级网关所提供的一种重要的安全功能,它的主要工作在开放系统互联(OSI)模型的对话层。主要的功能有: (1) 连接Internet与Intranet 充当firewall(防火墙)。因为所有内部网的用户通过代理服务器访问外界时,只映射为一个IP地址,所以外界不能直接访问到内部网。同时可以设置IP地址过滤,限制内部网对外部的访问权限。另外,两个没有互联的内部网,也可以通过第三方的代理服务器进行互联来交换信息。 (2) 节省IP开销。如前面所讲,所有用户对外只占用一个IP,所以不必租用过多的IP地址,降低网络的维护成本。这样,局域网内没有与外网相连的众多机器,通过内网的一台代理服务器连接到外网,大大减少费用。当然也有它不利的一面,如许多网络黑客通过这种方法隐藏自己的真实IP地址,而逃过监视。 (3) 提高访问速度。本身带宽较小,通过带宽较大的ProxyServer与目标主机连接。而且通常代理服务器都设置一个较大的硬盘缓冲区(可能高达几千兆字节更大),当外界的信息通过时,同时将其保存到缓冲区中,当他用户再访问相同的信息时,则直接由缓冲区中取出信息,传给用户,从而达到提高访问速度的目的。 对于智能爬虫系统来说,代理服务器主要起到两方面的作用: (1) 提高信息挖掘速度。由于网络速度的影响,直接访问对方Web服务器必然存在时间延迟,而如果使用了代理服务器,则可以从缓存中获取数据,大大提高系统性能。 (2) 避免被Web服务器防火墙屏蔽。由于有些Web服务器的防火墙设定了这样的规则:同一个IP一段时间内最多只能访问N次,一旦超过这个限度,就会当作是恶意访问而屏蔽。而如果智能爬虫系统通过不同的代理服务器去连接对方Web服务器的话,对方防火墙看到的是代理服务器的IP地址而不是爬虫系统所在的服务器IP,因此就可以避免因访问过于频繁而被防火墙屏蔽。 IRS 语言对代理服务器提供了如下的支持: ---------------------------------------- 系统配置 ' 代理=xxx.yyy.zzzz:8080' --------------------------------------- 2.10 JavaScript解析控制 动态HTML——DHTML是Dynamic HTML的缩写,DHTML通过传统的HTML语言,利用CSS(Cascading Style Sheets,即层叠式样式表),并依靠JavaScript使一向静止不变的页面得以“动”起来。NetScape 4.0和IE 4.0/5.0版本支持DHTML,DHTML是一种完全“客户端”技术,直接通过Web页面实现页面与用户之间的交互性。 DHTML的优秀之处在于增强了Web页面的功能,在Web页面直接建立动画、游戏和应用软件等等,提供了浏览站点的全新方式,与Java、Flash等技术不同的是,用DHTML编制的页面不需要插件的支持就能完整的实现这些功能。 JavaScript和它的名字表面意义恰巧相反,JavaScript和Java事实上没有任何联系,JavaScript是一种在页面中用于控制HTML元素的语言。JavaScript最早出现在NetScape 2.0,在这以后它的功能不断被完善和加强。 利用JavaScript可以动态地在网页的DOM树上增删节点,这使得我们在浏览器中看到的页面内容和HTML源码中显示的不一致,比如百度的图片搜索频道的结果页: http://image.baidu.com/i?ct=201326592&cl=2&lm-1&tn=baiduimage&pv=&word= %BC%C6%CB%E3%BB%FA&z=0。这个页面的HTML源码中并没有图片搜索结果地址,而浏览器中看到的如图2.1所示。 图2.1 在浏览器中所看到的页面 DOM树上的节点,实际上是通过HTML源码中的JavaScript代码执行之后,动态添加上去的。智能爬虫系统如果要从这种使用JavaScript动态生成的网页中提取出结构化信息,就必须具有像浏览器一样的执行JavaScript的能力。IRS语言提供了这种特性。 IRS语言的执行环境IRVM虚拟机能够识别并执行HTML源码中的JavaScript,构造完整的DOM树。但是由于JavaScript的执行代价比较高,如果页面中没有必须使用JavaScript才能提取到的信息,则可以关闭IRVM的JavaScript执行开关。相应的IRS语句如下: ------------------------------------------------------------------- 页面配置 页面名 '测试页' 入口 'http://xxx.com/abc.jsp' 配置:编码=UTF-8,JS=否. ; ------------------------------------------------------------------- 上述语句大致表达了这样的需求:用UTF-8编码,并且关闭JavaScript处理引擎,打开http://xxx.com/abc.jsp 这个页面进行数据挖掘。 |
相关讨论
相关资源推荐
- Struts2+Spring+Hibernate+Ehcache+AJAX+JQuery+Oracle 框架集成用户登录注册Demo工程
- java文件流读取异常_如何在异常情况下使文件流重新读取一行?
- java seek()方法
- springcloud+hibernate+JPA+EntityManager Oracle 双数据源配置
- 双oracle数据源配置,双数据源配置(一个项目中链接两个数据库)
- springboot+hibernate如何简单配置多个数据源
- SpringBoot Jpa多数据源(MySQL+Oracle不同数据库) 双数据源
- spring+hibernate 配置多个数据源过程 以及 spring中数据源的配置方式
- hibernate mysql datasource_使用hibernate配置多数据源链接MySQL和Oracle数据库
- springboot2+JPA 配置多数据源(不同类型数据库)