FrontierScheduler是一个PostProcessor,它的作用是将在Extractor中所分析得出的链接加入到Frontier中,以待继续处理。先来看一下FrontierScheduler的innerProcess()方法,代码如下。
上面的代码中,首先检查当前链接处理后的结果集中是否有一些属于高优先级的链接,如果是,则立刻转走进行处理。如果没有,则对所有的结果集进行遍历,然后调用Frontier中的schedule方法加入队列进行处理。 在这里,innerProcess()中并未立刻使用Frontier中的schedule()方法,而是增加了一层封装,先调用了一个类内部的protected类型的schedule()方法,进而在这个方法中再调用Frontier的schedule方法。这种方式对FrontierScheduler进行扩展留出了很好的接口。
例如,当有某个任务在抓取时,可能希望人为的去除符合某种条件的URL链接,使得其内容不会保存到本地。比如,要去除所有的扩展名为.zip、.exe、.rar、.pdf和.doc的链接(其实也就是不想下载这类文件)。可以通过继承FrontierScheduler,并重写内部的schedule方法来达到我们的需要。以下是一个示例。
protected void innerProcess(final CrawlURI curi) {
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.finest(getName() + " processing " + curi);
}
// 如果当前链接的处理结果中,有一些高优
// 先级的链接要被处理
if (curi.hasPrerequisiteUri() && curi.getFetchStatus() == S_DEFERRED) {
handlePrerequisites(curi);
return;
}
// 对当前这个Processor进行同步
synchronized(this) {
// 从处理结果中,取出所有链接进行循环
for (final Iterator iter = curi.getOutLinks().iterator();
iter.hasNext();) {
Object obj = iter.next();
CandidateURI cauri = null;
// 转型为CandidateURI
if (obj instanceof CandidateURI) {
cauri = (CandidateURI)obj;
} else {
LOGGER.severe("Unexpected type: " + obj);
}
// 调用schedule()方法
if (cauri != null) {
schedule(cauri);
}
}
}
}
protected void schedule(CandidateURI caUri) {
// 调用Frontier中的schedule()方法
// 将传入的链接加入到等待队列中
getController().getFrontier().schedule(caUri);
}
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.finest(getName() + " processing " + curi);
}
// 如果当前链接的处理结果中,有一些高优
// 先级的链接要被处理
if (curi.hasPrerequisiteUri() && curi.getFetchStatus() == S_DEFERRED) {
handlePrerequisites(curi);
return;
}
// 对当前这个Processor进行同步
synchronized(this) {
// 从处理结果中,取出所有链接进行循环
for (final Iterator iter = curi.getOutLinks().iterator();
iter.hasNext();) {
Object obj = iter.next();
CandidateURI cauri = null;
// 转型为CandidateURI
if (obj instanceof CandidateURI) {
cauri = (CandidateURI)obj;
} else {
LOGGER.severe("Unexpected type: " + obj);
}
// 调用schedule()方法
if (cauri != null) {
schedule(cauri);
}
}
}
}
protected void schedule(CandidateURI caUri) {
// 调用Frontier中的schedule()方法
// 将传入的链接加入到等待队列中
getController().getFrontier().schedule(caUri);
}
protected void schedule(CandidateURI caUri) {
String url = caUri.toString();
if (url.endsWith(".zip")
|| url.endsWith(".rar")
|| url.endsWith(".exe")
|| url.endsWith(".pdf")
|| url.endsWith(".doc")
|| url.endsWith(".xls")) {
return;
}
getController().getFrontier().schedule(caUri);
}
String url = caUri.toString();
if (url.endsWith(".zip")
|| url.endsWith(".rar")
|| url.endsWith(".exe")
|| url.endsWith(".pdf")
|| url.endsWith(".doc")
|| url.endsWith(".xls")) {
return;
}
getController().getFrontier().schedule(caUri);
}
这样,每当Heritrix在执行任务时,遇到这样的文件,就会跳过抓取,从而达到了对URL链接进行筛选的目的。
这个到后面真正抓取的时候也是很有用的