本博客属原创文章,欢迎转载!转载请务必注明出处:http://guoyunsky.iteye.com/blog/649889
欢迎加入Heritrix群(QQ):109148319
Url是爬虫的核心,因为爬虫就是依赖URL一层一层的抓取下去,最后完成整个抓取。Heritrix中的URL比较特殊,有以下继承关系(由于不对继承关系作介绍,所以这里就不画图了):
1)org.archive.crawler.datamodel.CrawlURI——>CandidateURI
2)org.archive.net.UURI——>org.archive.net.LaxURI
——>org.apache.commons.httpclient.URI——>java.net.URL
前面说过CrawlURI和CandidateURI的区别在于CrawlURI是由通过了调度器(Frontier)的CandidateURI转换而来的。下面就先介绍CnadidateURI(主要介绍相关属性):
public static final int HIGH = 1; //调度器调度等级:高 public static final int HIGHEST = 0; //调度器调度等级:最高 public static final int MEDIUM = 2; //调度器调度等级:中 public static final int NORMAL = 3; //调度器调度等级:普通 //URL字符串 private String cachedCandidateURIString = null; //队列Key,不同队列有不同的classKey.其中相同classKey的CandidateURI则属于相同的队列 private String classKey; //是否强制访问,强制访问的话会重复抓取 private boolean forceRevisit = false; // 是不是种子 private boolean isSeed = false; /** * 灵活的属性列表,Heritrix在运行过程中需要保存不固定的属性和属性值, *同时扩展Heritrix属性 也可以放在里面。不过需要特殊处理,等下单独介绍 */ private transient AList alist; /** * 该值代表当前CandidateURI是如何从种子那里生成的,有如下生成方式: * P:预先处理URL,一般是DNS,如DNS:www.baidu.com * R:重定向URL * E:嵌入式URL,如Frame、src等 * X:特殊嵌入式URL,如JS中的URL * L:一般意义上的URL,如 * 该属性除了可以记录从种子那来源方式的话同时还可以记录深度,因为 * 该值是一层一层传递,每传递一层则增加一个以上字符.如此通过长度 * 可以判断当前URL属于种子的第几层从而做到控制抓取深度, 如果当 * 前CandidateURI是种子,则该值为null */ private String pathFromSeed; private int schedulingDirective = NORMAL; // 调度等级,默认为普通 private transient UURI uuri; //URL private transient UURI via; //来源URL private CharSequence viaContext;//来源URL内容
下面再介绍一下CrawlURI相关属性,前面说过CrawlURI和CandidateURI最大区别就是CrawlURI通过了调度器,这也就意味着CrawlURI会进入队列抓取,如此CrawlURI就会相比CandidateURI对很多属性来记录抓取情况,如处理器,下面请看代码以及注释:
//数组用户保存alist成员的key,使得URI处理期间可以持久化访问.这个list中的所有的key在传递下去的处理链 后面都不会被清理掉 private static final List
同时很多人在使用Heritrix的时候需要增加自己的属性,我之前也有这样的需求。不过那时是直接修改源代码增加几个属性,然后在抽取的时候将新的属性赋给抽取出来的URL即可。后来才发现完全没有这个必要,Heritrix已经提供了这样一个功能,可以自定义放入各种属性和属性值。同时Heritrix自己在运行过程中也是如此,把一些会动态变化的属性放入其中,如HttpStatus Code。下面就介绍下其相关原理以及如何使用这个功能:
1)原理:
CandidateURI里面有一个属性private transient AList alist;该属性实际上是一个HashTable,其中Key为属性,Value为属性值。如此一致贯穿整个抓取,可以随时动态读写。但由于该属性是transient,也就意味着HashTable里面的值不会被持久化,所以Heritrix在CrawlURI里面引入一个个变量来记录HashTable中需要持久化的Key,也就是我们所要持久化的属性了:private static final List
2)使用方法:
1.存放属性和属性值,变量可以按多种类型存放:
//放入类型为Int的值 public void putInt(String key, int value) { getAList().putInt(key, value); } //放入类型为Long的属性值 public void putLong(String key, long value) { getAList().putLong(key, value); } //放入类型为Object的属性值 public void putObject(String key, Object value) { getAList().putObject(key, value); } //放入类型为String的属性值 public void putString(String key, String value) { getAList().putString(key, value); }
2.获得属性和属性值:
//获得属性的值,该值为Int类型 public int getInt(String key) { return getAList().getInt(key); } //获得属性的值,该值为Long类型 public long getLong(String key) { return getAList().getLong(key); } //获得属性的值,该值为Object类型 public Object getObject(String key) { return getAList().getObject(key); } //获得属性的值,该值为String类型 public String getString(String key) { return getAList().getString(key); }
3.查看是否包含某个属性:
//查看是否包含某个属性 public boolean containsKey(String key) { return getAList().containsKey(key); }
4.获得所有的属性:
//返回所有的属性值 public Iterator keys() { return getAList().getKeys(); }
5.让某个属性持久化:
public void makeHeritable(String key) { @SuppressWarnings("unchecked") ListheritableKeys = (List ) getObject(A_HERITABLE_KEYS); if (heritableKeys == null) { heritableKeys = new ArrayList (); heritableKeys.add(A_HERITABLE_KEYS); putObject(A_HERITABLE_KEYS, heritableKeys); } heritableKeys.add(key); }
6.让某个属性不持久化:
public void makeNonHeritable(String key) { List heritableKeys = (List) getObject(A_HERITABLE_KEYS); if (heritableKeys == null) { return; } heritableKeys.remove(key); if (heritableKeys.size() == 1) { // only remaining heritable key is itself; disable completely remove(A_HERITABLE_KEYS); } }
以上6个介绍完全可以让你扩展自己的属性以及让他们持久化,如果还有其他问题,请留言,或者加入群:10447185
更多技术文章、感悟、分享、勾搭,请用微信扫描: