4 功能模块的设计与实现
4.1. 爬虫机器人模块的设计与实现
本系统因为是只针对农业进行垂直搜索,所以爬虫只爬相关的主题内容,所以采取聚焦爬虫的方式进行。聚焦爬虫,又称主题爬虫(或专业爬虫),是“面向特定主题”的一种网络爬虫程序。它与我们通常所说的爬虫(通用爬虫)的区别之处就在于,聚焦爬虫在实施网页抓取时要进行主题筛选。它尽量保证只抓取与主题相关的网页信息。
4.1.1 农业主题爬虫的工作流程
本系统的主题爬虫主要采用Heritrix技术,开始时先根据种子URL下载源页面,然后解析页面并把符合主题的URL加入队列,最后不断递归队列中的URL重复上述操作。
4.1.2 基于Heritrix的爬虫设计与实现
(1)Heritrix简介
Heritrix是一个Java开发,开源web爬虫程序,用户可以使用它来从互联网上抓住想要的资源。最突出的是它可伸缩性好,容易实现他们获取逻辑。它的执行进行递归,主要有以下几步:
1。在预定的URI中选择一个。
2。获取URI
3。分析,归档结果
4。选择已经发现的感兴趣的URI。加入预定队列。
5。标记已经处理过的URI
它的设计原理图如图4-2所示:
图4-2 Heritrix设计架构图
(2)Heritrix 的自定义主题抓取
Hetiitrix 主题策略抓取主要分两种:基于链接和基于内容。
基于链接:扩展FrontierScheduler (是否作为候选URL,每个候选URL都创建一个线程)和扩展Extractor(对于页面的内容是否进行抽取)
核心代码的实现:
public classMyFrontierScheduler extends FrontierScheduler { private static final long serialVersionUID =-1074778906898000967L; /** * @param nameName of this filter. */ publicMyFrontierScheduler(String name) { super(name); } @Override protected voidschedule(CandidateURI caUri) { if(caUri.toString().contains("news")){ System.out.println(caUri.toString()); getController().getFrontier().schedule(caUri); } } } |
基于内容的主题抓取,核心代码为:
public class MyExtractor extends Extractor{ private String HERF ="<a(.*)href\\s*=\\s*(\"([^\"]*)\"|([^\\s>]*))(.*)>"; private String sinaUrl ="http://(.*)news.sina.com.cn(.*).shtml"; public MyExtractor(Stringname, String description) { super(name,description); } public MyExtractor(String name) { super(name, "sinaextrator"); } private static final longserialVersionUID = -963034874191929396L;
@Override protected voidextract(CrawlURI curi) { String url=""; try { HttpRecorder hr =curi.getHttpRecorder(); if(null == hr){ throw newException("httprecorder is null"); } ReplayCharSequence rc = hr.getReplayCharSequence(); if(null == rc){ return ; } String context =rc.toString();
Pattern pattern =Pattern.compile(HERF,Pattern.CASE_INSENSITIVE); Matcher matcher =pattern.matcher(context); while(matcher.find()){ url =matcher.group(2); url =url.replace("\"", ""); //System.out.println(url); if(url.matches(sinaUrl)){ System.out.println(url); <span style="color:#ff0000;">curi.createAndAddLinkRelativeToBase(url, context,Link.NAVLINK_HOP);</span> } } } catch (Exception e) { e.printStackTrace(); } } } |
4.1.3 基于Heritrix爬虫的线程优化
应用ELFHash 算法优化开启线程策略。在默认的情况下,Heritrix使用HostnameQueueAssignmentPolicy来产生key值,而这个策略是用hostname作为key值的,因此一个域名下的所有链接都会被放在同一个线程中去。如果对Heritrix分配URI时的策略进行改进,利用ELFHash“可执行链接格式”(Executable and Linking Format,即ELF)算法把url尽量平均分布到各个队列中去,就能用较多的线程同时抓取一个域名下的网页,速度将得到大大的提高。
ELFHash算法的实现如下:
// ELF Hash Function unsigned int ELFHash(char *str) { int hash = 0; int x = 0;
while (*str) { hash = (hash << 4) + (*str++);//hash左移4位,把当前字符ASCII存入hash低四位。 if ((x = hash & 0xF0000000L) != 0) { //该处理,如果最高位为0,就会仅仅影响5-8位,否则会影响5-31位,因为C语言使用的算数移位 //因为1-4位刚刚存储了新加入到字符,所以不能>>28 hash ^= (x >> 24); //上面这行代码并不会对X有影响,本身X和hash的高4位相同,下面这行代码&~即对28-31(高4位)位清零。 hash &= ~x; } } //返回一个符号位为0的数,即丢弃最高位,以免函数外产生影响。(我们可以考虑,如果只有字符,符号位不可能为负) return (hash & 0x7FFFFFFF); }
|
优化前:对于同一个网站,Heritrix只会分配一个线程去处理数据,一分钟只抓取到28个网页。而优化后,Heritrix会分配5-15个线程同时去处理一个网站的数据,一分钟抓取网页的数量为1300个左右。
图4-3 优化前线程数量
图4-4 优化前每分钟页面下载数
图4-5 优化后线程数量
图4-6 优化后每分钟下载的页面数量
4.1.3 Heritrix的工具化
为了方便开发,我们需要定制Heritrix然后打包,作为一个工具来使用。
为此我们需要:
1) 免登陆
2) 统一输出路径
3) 默认order.xml
4) 用bat启动并加载自己的heritrix.jar
1. 免登陆
在webapp的web.xml中把安全过滤的后缀.Jsp改为其他后缀
2. 统一输出路径
在org.archive.crawler.admin这个包中有很多与操作界面相关的后台逻辑处理
找到CrawlJobHandler.java,寻找“jobdir”看看那些有“-”相关的代码,修改命名方式即可。
3. 默认order.xml
打开之前设定的jobs文件夹的工作,然后将order.xml复制到工程默认即可。
4. 用bat启动并加载自己的heritrix.jar
把工程打包成jar包,覆盖原例子程序的admin,conf;编写bat文件。