本博客属原创文章,欢迎转载!转载请务必注明出处:http://guoyunsky.iteye.com/blog/649889

本博客已迁移到本人独立博客: http://www.yun5u.com/

       欢迎加入Heritrix群(QQ):109148319,10447185 , Lucene/Solr群(QQ) :  118972724

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(主要介绍相关属性):

  1. public static final int HIGH = 1;                  //调度器调度等级:高
  2. public static final int HIGHEST = 0;          //调度器调度等级:最高
  3. public static final int MEDIUM = 2; //调度器调度等级:中
  4. public static final int NORMAL = 3; //调度器调度等级:普通
  5. //URL字符串
  6. private String cachedCandidateURIString = null;
  7. //队列Key,不同队列有不同的classKey.其中相同classKey的CandidateURI则属于相同的队列
  8. private String classKey;
  9. //是否强制访问,强制访问的话会重复抓取
  10. private boolean forceRevisit = false;
  11. // 是不是种子
  12. private boolean isSeed = false;
  13. /**
  14. * 灵活的属性列表,Heritrix在运行过程中需要保存不固定的属性和属性值,
  15. *同时扩展Heritrix属性 也可以放在里面。不过需要特殊处理,等下单独介绍
  16. */
  17. private transient AList alist;
  18. /**
  19. * 该值代表当前CandidateURI是如何从种子那里生成的,有如下生成方式:
  20. * P:预先处理URL,一般是DNS,如DNS:www.baidu.com
  21. * R:重定向URL
  22. * E:嵌入式URL,如Frame、src等
  23. * X:特殊嵌入式URL,如JS中的URL
  24. * L:一般意义上的URL,如<a href="www.baidu.com">
  25. * 该属性除了可以记录从种子那来源方式的话同时还可以记录深度,因为
  26. * 该值是一层一层传递,每传递一层则增加一个以上字符.如此通过长度
  27. * 可以判断当前URL属于种子的第几层从而做到控制抓取深度, 如果当
  28. * 前CandidateURI是种子,则该值为null
  29. */
  30. private String pathFromSeed;
  31. private int schedulingDirective = NORMAL; // 调度等级,默认为普通
  32. private transient UURI uuri;          //URL
  33. private transient UURI via;       //来源URL
  34. private CharSequence viaContext;//来源URL内容

下面再介绍一下CrawlURI相关属性,前面说过CrawlURI和CandidateURI最大区别就是CrawlURI通过了调度器,这也就意味着CrawlURI会进入队列抓取,如此CrawlURI就会相比CandidateURI对很多属性来记录抓取情况,如处理器,下面请看代码以及注释:

  1. //数组用户保存alist成员的key,使得URI处理期间可以持久化访问.这个list中的所有的key在传递下去的处理链 后面都不会被清理掉
  2. private static final List<Object> alistPersistentMember = new CopyOnWriteArrayList<Object>(
  3. new String[] { A_CREDENTIAL_AVATARS_KEY });
  4. // 一个CrawlURI所允许的最大外链接数(就是该CrawlURI本身网页里所包含的链接数),默认为6000
  5. public static final int MAX_OUTLINKS = Integer.parseInt(System.getProperty(
  6. CrawlURI.class.getName() + ".maxOutLinks", "6000"));
  7. // 放弃的外链接个数(当一个URL抽取出来的链接数超过MAX_OUTLINKS时就放弃,然后本变量累加)
  8. transient private int discardedOutlinks = 0;
  9. public static final int UNCALCULATED = -1; //网页内容长度,默认值
  10. private String cachedCrawlURIString = null; //缓存的URL
  11. private byte[] contentDigest = null; //网页内容指纹,对内容进行MD5值,该对象可以用于对比该URL是否有更新
  12. private String contentDigestScheme = null; // 记录网页内容所采用算法,从配置文件里配置
  13. private long contentLength = UNCALCULATED; //相应内容长度
  14. private long contentSize = UNCALCULATED; //网页内容大小
  15. private String contentType = null; //网页内容类型
  16. private int deferrals = 0;      //从先决条件URL延迟数
  17. private int fetchAttempts = 0;  // 获取URL的个数
  18. private int fetchStatus = 0;    //获取URL内容状态,默认为0,表示没有尝试过
  19. transient Object holder;        // 所属的队列(WorkQueue)
  20. int holderCost = UNCALCULATED;  //成本
  21. transient Object holderKey;     //所属队列的classkey
  22. private transient HttpRecorder httpRecorder = null; //记录网页内容
  23. transient private boolean linkExtractorFinished = false; //抽取是否成功,如果成功则该URL不会再被抽取
  24. transient private Processor nextProcessor; // 下一个处理器
  25. transient private ProcessorChain nextProcessorChain;// 下一条处理链
  26. protected long ordinal; //Crawl自增数目,用于广度优先抓取
  27. transient Collection<Object> outLinks = new HashSet<Object>();   //该URL抽取到的所有的连接
  28. private boolean post = false; // 提交url是否post,对应HttpClient的HttpPost
  29. private boolean prerequisite = false; //是否有优先URL要处理,一般是DNS
  30. transient private int threadNumber; //线程个数
  31. private String userAgent = null;    //用户代理,表名当前身份
  32. @Deprecated
  33. private int embedHopCount = UNCALCULATED;
  34. @Deprecated
  35. private int linkHopCount = UNCALCULATED; // 跃点数,表示来自种子的第几层,该值可以控制抓取深度

同时很多人在使用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<Object> alistPersistentMember = new CopyOnWriteArrayList<Object>( new String[] { A_CREDENTIAL_AVATARS_KEY });该属性类型为CopyOnWriteArrayList,也就是专门用于复制写的List,里面存放需要持久化的Key。所以当你需要某个HashTable中的某个Key持久化的时候,只需要在该变量里添加即可。

2)使用方法:

1.存放属性和属性值,变量可以按多种类型存放:

  1. //放入类型为Int的值
  2. public void putInt(String key, int value) {
  3. getAList().putInt(key, value);
  4. }
  5. //放入类型为Long的属性值
  6. public void putLong(String key, long value) {
  7. getAList().putLong(key, value);
  8. }
  9. //放入类型为Object的属性值
  10. public void putObject(String key, Object value) {
  11. getAList().putObject(key, value);
  12. }
  13. //放入类型为String的属性值
  14. public void putString(String key, String value) {
  15. getAList().putString(key, value);
  16. }

2.获得属性和属性值:

  1. //获得属性的值,该值为Int类型
  2. public int getInt(String key) {
  3. return getAList().getInt(key);
  4. }
  5. //获得属性的值,该值为Long类型
  6. public long getLong(String key) {
  7. return getAList().getLong(key);
  8. }
  9. //获得属性的值,该值为Object类型
  10. public Object getObject(String key) {
  11. return getAList().getObject(key);
  12. }
  13. //获得属性的值,该值为String类型
  14. public String getString(String key) {
  15. return getAList().getString(key);
  16. }

3.查看是否包含某个属性:

  1. //查看是否包含某个属性
  2. public boolean containsKey(String key) {
  3. return getAList().containsKey(key);
  4. }

4.获得所有的属性:

  1. //返回所有的属性值
  2. public Iterator keys() {
  3. return getAList().getKeys();
  4. }

5.让某个属性持久化:

  1. public void makeHeritable(String key) {
  2. @SuppressWarnings("unchecked")
  3. List<String> heritableKeys = (List<String>) getObject(A_HERITABLE_KEYS);
  4. if (heritableKeys == null) {
  5. heritableKeys = new ArrayList<String>();
  6. heritableKeys.add(A_HERITABLE_KEYS);
  7. putObject(A_HERITABLE_KEYS, heritableKeys);
  8. }
  9. heritableKeys.add(key);
  10. }

6.让某个属性不持久化:

  1. public void makeNonHeritable(String key) {
  2. List heritableKeys = (List) getObject(A_HERITABLE_KEYS);
  3. if (heritableKeys == null) {
  4. return;
  5. }
  6. heritableKeys.remove(key);
  7. if (heritableKeys.size() == 1) {
  8. // only remaining heritable key is itself; disable completely
  9. remove(A_HERITABLE_KEYS);
  10. }
  11. }

以上6个介绍完全可以让你扩展自己的属性以及让他们持久化,如果还有其他问题,请留言,或者加入群:10447185

Heritrix源码分析(十一) Heritrix中的URL--CandidateURI和CrawlURI以及如何增加自己的属性(转)的更多相关文章

  1. Heritrix源码分析(九) Heritrix的二次抓取以及如何让Heritrix抓取你不想抓取的URL

    本博客属原创文章,欢迎转载!转载请务必注明出处:http://guoyunsky.iteye.com/blog/644396       本博客已迁移到本人独立博客: http://www.yun5u ...

  2. Heritrix源码分析(十三) Heritrix的控制中心(大脑)CrawlController(二)

    本博客属原创文章,欢迎转载!转载请务必注明出处:http://guoyunsky.iteye.com/blog/650744      本博客已迁移到本人独立博客: http://www.yun5u. ...

  3. Heritrix源码分析(七) Heritrix总体介绍(转)

    本博客属原创文章,欢迎转载!转载请务必注明出处:http://guoyunsky.iteye.com/blog/642794         本博客已迁移到本人独立博客: http://www.yun ...

  4. Heritrix源码分析(十) Heritrix中的Http Status Code(Http状态码)(转)

    本博客属原创文章,欢迎转载!转载请务必注明出处:http://guoyunsky.iteye.com/blog/649737       本博客已迁移到本人独立博客: http://www.yun5u ...

  5. Heritrix源码分析(六) Heritrix的文件结构分析(转)

    本博客属原创文章,欢迎转载!转载请务必注明出处:http://guoyunsky.iteye.com/blog/642618      本博客已迁移到本人独立博客: http://www.yun5u. ...

  6. Heritrix源码分析(十四) 如何让Heritrix不间断的抓取(转)

    欢迎加入Heritrix群(QQ):109148319,10447185 , Lucene/Solr群(QQ) :  118972724 本博客已迁移到本人独立博客: http://www.yun5u ...

  7. Heritrix源码分析(十四)

    近段时间在搞定Lucene的一些问题,所以Heritrix源码分析暂时告一段落.今天下午在群里有同学提到了Heritrix异常终止的问题以及让Heritrix不停的抓取(就是抓完一遍后载入种子继续抓取 ...

  8. angular源码分析:angular中脏活累活的承担者之$interpolate

    一.首先抛出两个问题 问题一:在angular中我们绑定数据最基本的方式是用两个大括号将$scope的变量包裹起来,那么如果想将大括号换成其他什么符号,比如换成[{与}],可不可以呢,如果可以在哪里配 ...

  9. angular源码分析:angular中入境检察官$sce

    一.ng-bing-html指令问题 需求:我需要将一个变量$scope.x = '<a href="http://www.cnblogs.com/web2-developer/&qu ...

随机推荐

  1. bat批处理延迟运行脚本(zz)

    @echo off:aaapause 这里是你需要运行的程序for /l %%i in (0,1,10000) do echo %%i>nulgoto aaa 当然bat延迟运行还有其他的一些方 ...

  2. sizeof学习理解

    以下内容转自: http://www.cnblogs.com/ComputerG/archive/2012/02/02/2335611.html 博问 闪存 首页 新随笔 联系 管理 随笔- 72  ...

  3. Node.js缓冲模块Buffer

    前言 Javascript是为浏览器而设计的,能很好的处理unicode编码的字符串,但对于二进制或非unicode编码的数据就显得无能为力. Node.js继承Javascript的语言特性,同时又 ...

  4. C# Task的使用---Task的启动

    .NET 4.0包含的新名称空间System.Threading.Tasks,它包含的类抽象出了线程功能.任务表示应完成的某个单元的工作.这个单元的工作可以在单独的线程中运行,也可以以同步的方式启动一 ...

  5. iOS开发--开发者帐号

    iOS应用上线 http://www.jianshu.com/p/ffddc5e5f0b9 http://www.jianshu.com/p/986e02d38f1b 好不容易终于申请下来了ios 公 ...

  6. updmap-sys failed. Output has been stored in

    Ubuntu 12.04升级到Ubuntu 12.04lts的时候,出现错误: Do you want to continue? [Y/n] ySetting up tex-common (4.04) ...

  7. 对QT的理解——能在公司里不做Java,不做很偏门的产品,不使用偏门的语言,还有钱挣,要有感恩的心

    我的理解: QT做应用软件可以很强大,界面足够漂亮(最有意思的是QSS,让我刮目相看),应该是足够了.同时QT也提供了源码,不过超级复杂,难以理解,所以还是无法深入底层.另外它提供了一个额外的好处,就 ...

  8. IOS 的loadView 及使用loadView中初始化View注意的问题。(死循环并不可怕)

    在XCode 4.2后,我基本上的应用都不使用Xib文件了,虽然xib文件有很多好趣,可以快速免代码构建视窗,可以减少好多代码构建带来的麻烦,其实能用xib还是不错的,主要是我的机器打开xib来编辑时 ...

  9. 关于LINUX权限-bash: ./startup.sh: Permission denied

    关于LINUX权限-bash: ./startup.sh: Permission denied <script type="text/javascript"></ ...

  10. python实现全角半角的相互转换

    缘起 在自然语言处理过程中,全角.半角的的不一致会导致信息抽取不一致,因此需要统一. 转换说明 全角半角转换说明 有规律(不含空格): 全角字符unicode编码从65281~65374 (十六进制 ...