Heritrix3.3.0有一个很实用的功能,就是在抓取开始之后,依然可以通过在指定目录里放入种子文件的方式向爬虫添加新的种子。接下来,我们就来看看这个功能是怎样实现的。
这个功能是在org.archive.crawler.framework包下的ActionDirectory类实现的,这个类去掉内容后是这个样子的:
public class ActionDirectory implements ApplicationContextAware, Lifecycle, Runnable
/** * Action taken at scheduled intervals * @see java.lang.Runnable#run() */ public void run() { scanActionDirectory(); }
/** * Find any new files in the 'action' directory; process each in * order. * * 在action目录下寻找新文件 */ protected void scanActionDirectory() { File dir = actionDir.getFile(); File[] files = dir.listFiles((FileFilter)FileFilterUtils.fileFileFilter()); Arrays.sort(files); for(File f : files) { try { actOn(f); } catch (Throwable e) { LOGGER.log(Level.SEVERE,"unhandled exception from actifile: "+f,e); } } }
首先看看存放新文件的目录action的声明:
protected ConfigPath actionDir = new ConfigPath("ActionDirectory source directory","action");
从scanActionDirectory方法中可以看到,发现的新文件交给了actOn方法。这个方法在Heritrix3.3.0源码阅读 种子模块(观察者模式实践)一文中已经讲过,它用于从种子文件中读取种子,并发布给观察者。
到此,我们已经清楚了ActionDirectory类加载种子文件和发布种子的流程。接下来,就来看看ActionDirectory如何利用这个流程来实现“动态”载入种子的。其实我们自己就能猜出来,应该是用定时任务,事实也是这样的。
ActionDirectory类里有这个方法:
public void start() { if (isRunning()) { return; } try { // create directories org.archive.util.FileUtils.ensureWriteableDirectory(getActionDir().getFile()); org.archive.util.FileUtils.ensureWriteableDirectory(getDoneDir().getFile()); } catch (IOException e) { throw new IllegalStateException(e); } // start background executor executor = Executors.newSingleThreadScheduledExecutor(); executor.scheduleWithFixedDelay(this, getInitialDelaySeconds(), getDelaySeconds(), TimeUnit.SECONDS); }
到此,我们搞清楚了Heritrix3.3.0是如何实现动态载入种子的了:用一个定时任务从指定目录加载种子文件,发布文件里的种子。