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

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

近段时间在搞定Lucene的一些问题,所以Heritrix源码分析暂时告一段落。今天下午在群里有同学提到了Heritrix异常终止的问题以及让Heritrix不停的抓取(就是抓完一遍后载入种子继续抓取,目前他是写个定时器,定时检查Heritrix是否停止,如果停止了则重新初始化Heritrix,让Heritrix重新抓取,但这个方法就不可避免的会导致抓取重复URl,除非从recover.gz导入)。我想这2个问题都可以用我下面这个方法,但对于Heritrix异常终止的问题这个方法也只是治标不治本,要改动的地方蛮多,涉及到Heritrix的设计以及结构,不是一时可以完成。下面就介绍原理以及方法:

1.原理:

      Heritrix的自然停止(就是非人为以及不可抗力因素,如Web UI界面出发停止命令)的依据是判断调度器里面是否还有URL可抓取,如果没有则当前线程退出,如果是单线程抓取的话,则也意味着Heritrix的结束。如果是多线程抓取的话,则每个线程在获取不到URL的时候都会置不在活动状态,当最后一个活动状态线程也获取不到URL的时候则Heritrix也会进入自然停止。所以我们可以在判断Heritrix是否还有URL可抓取的时候做一些处理,比较简单的方法就是重新载入种子以及唤醒所有抓取线程。但由于处在多线程抓取模式中,每个线程都会判断,如此会导致多次载入种子,造成不必要的浪费,所以这里也要做一些同步控制。不要导致过分载入种子,而是每抓完一次则重新载入种子。

2.方法:

    修改org.archive.crawler.frontier.WorkQueueFrontier中的public CrawlURI next()方法,这里也对该方法做一些介绍,具体请看源码注释,改成如下,红色部分为改动部分:

  1. /**
  2. * 从调度中心获取下一个要抓取的URL
  3. *
  4. */
  5. public CrawlURI next() throws InterruptedException, EndedException {
  6. while (true) {//一直不停的循环,直到遇到异常或终止
  7. <span style="color: #ff0000;">// 郭芸修改,用于当队列里没有可抓取的URL的时候去获取种子继续
  8. synchronized (this) {
  9. if (this.controller.getFrontier().isEmpty()) {  //如果没有可抓取的URL
  10. loadSeeds();    //重新载入种子
  11. this.controller.getToePool().notifyAll();   //唤醒所有抓取线程
  12. }
  13. }</span>
  14. long now = System.currentTimeMillis();//开始获取时间
  15. // 检查是否有暂停命令、结束命令以及宽带控制,这里会导致Heritrix结束
  16. preNext(now);
  17. /*
  18. * 允许最多一个线程去填充准备队列(readyClassQueues)
  19. */
  20. if (readyFiller.tryAcquire()) {// 表示没有线程去使用当前变量,当前类1次只允许1个线程同时使用
  21. try {
  22. // 空闲队列数=目标队列数-准备队列数
  23. int activationsNeeded = targetSizeForReadyQueues()
  24. - readyClassQueues.size();
  25. // 如果空闲队列数大于0,并且不在活动状态的队列数不是空的,则表示需要将不在活动状态的队列转移到准备队列
  26. while (activationsNeeded > 0 && !inactiveQueues.isEmpty()) {
  27. activateInactiveQueue();//将不在活动状态队列的URL转移一定数目到活动状态队列
  28. activationsNeeded--;
  29. }
  30. } finally {
  31. readyFiller.release();// 必须释放,这样下次才可以继续使用
  32. }
  33. }
  34. WorkQueue readyQ = null;//准备工作队列
  35. // 获取并移除此准备队列表示的队列的头部(即准备队列的第一个元素)如果该队列没有可用元素,则等待指定的时间,这里是1000毫秒也就是1秒
  36. Object key = readyClassQueues.poll(DEFAULT_WAIT,TimeUnit.MILLISECONDS);// 获得classKey,然后再通过classKey去获得队列
  37. if (key != null) {
  38. readyQ = (WorkQueue) this.allQueues.get(key);// 获得工作队列WorkQueue
  39. }
  40. if (readyQ != null) {
  41. while (true) { // 一直循环,直到抛出异常或终止
  42. CrawlURI curi = null;
  43. synchronized (readyQ) {//锁定准备队列,让其他线程无法获取,避免脏读
  44. curi = readyQ.peek(this); // 从数据库pendingUrls中获取CrawlURI
  45. if (curi != null) {
  46. // 检查该curi是否属于不同的队列
  47. String currentQueueKey = getClassKey(curi);
  48. if (currentQueueKey.equals(curi.getClassKey())) {
  49. //在正确的队列,排放它
  50. noteAboutToEmit(curi, readyQ);
  51. inProcessQueues.add(readyQ);// 加入已处理队列
  52. return curi;
  53. }
  54. curi.setClassKey(currentQueueKey);
  55. readyQ.dequeue(this);       //从调度器中删除刚获取到的URL
  56. decrementQueuedCount(1);    //计数
  57. curi.setHolderKey(null);
  58. } else {
  59. readyQ.clearHeld();
  60. break;
  61. }
  62. }
  63. if (curi != null) {
  64. sendToQueue(curi);  //将获取到的URL发送到它该属于的队列
  65. }
  66. }
  67. } else {
  68. if (key != null) {
  69. logger.severe("Key " + key
  70. + " in readyClassQueues but not allQueues");
  71. }
  72. }
  73. //如果该强烈退出,则抛异常结束循环
  74. if (shouldTerminate) {
  75. throw new EndedException("shouldTerminate is true");
  76. }
  77. //如果没有处理中的队列,则刷新该队列
  78. if (inProcessQueues.size() == 0) {
  79. this.alreadyIncluded.requestFlush();
  80. }
  81. }
  82. }

Heritrix源码分析(十四) 如何让Heritrix不间断的抓取(转)的更多相关文章

  1. Heritrix源码分析(十四)

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

  2. Heritrix源码分析(三) 修改配置文件order.xml加快你的抓取速度(转)

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

  3. Heritrix源码分析(十五) 各种问题总结(转)

    开博客以及建立Heritrix 群有一段时间了(这里谢谢大家的关注),这篇博客将整理这段时间所遇到的问题.同时由于自己从今年5月份开始就不怎么接触Heritrix,很多东西开始遗忘(不过里面思想没忘) ...

  4. Heritrix源码分析(十五)

    开博客以及建立Heritrix 群有一段时间了(这里谢谢大家的关注),这篇博客将整理这段时间所遇到的问题.同时由于自己从今年5月份开始就不怎么接触Heritrix,很多东西开始遗忘(不过里面思想没忘) ...

  5. ABP源码分析十四:Entity的设计

    IEntity<TPrimaryKey>: 封装了PrimaryKey:Id,这是一个泛型类型 IEntity: 封装了PrimaryKey:Id,这是一个int类型 Entity< ...

  6. jQuery 源码分析(十四) 数据操作模块 类样式操作 详解

    jQuery的属性操作模块总共有4个部分,本篇说一下第3个部分:类样式操作部分,用于修改DOM元素的class特性的,对于类样式操作来说,jQuery并没有定义静态方法,而只定义了实例方法,如下: a ...

  7. Vue.js 源码分析(十四) 基础篇 组件 自定义事件详解

    我们在开发组件时有时需要和父组件沟通,此时可以用自定义事件来实现 组件的事件分为自定义事件和原生事件,前者用于子组件给父组件发送消息的,后者用于在组件的根元素上直接监听一个原生事件,区别就是绑定原生事 ...

  8. Heritrix源码分析(十二) Heritrix的控制中心(大脑)CrawlController(一)(转)

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

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

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

随机推荐

  1. 动态调用wcf接口服务

    1.url:http://localhost:8002/名称.svc/basic(.svc结尾) 2.需要引用的命名空间System.ServiceModel 3.调用代码: public class ...

  2. Linux客户/服务器程序设计范式2——并发服务器(进程池)

    引言 让服务器在启动阶段调用fork创建一个子进程池,通过子进程来处理客户端请求.子进程与父进程之间使用socketpair进行通信(为了方便使用sendmsg与recvmsg,如果使用匿名管道,则无 ...

  3. Linux多线程之同步3

    需求 客户端将需要解决的task发送给服务器,服务器调用线程来解决客户端发送的task,解决完由线程负责将其发送回客户端.(用管道实现通信) 思路 1. server维护两个列表.一是客户端列表.二是 ...

  4. notepad++使用技巧及插件汇总

    NppAutoIndent 自动缩进CCompletion 自动补全.TextFX 插件nppFTP 运行程序 ============================================ ...

  5. Passing JavaScript Objects to Managed Code

    Silverlight If the target managed property or input parameter is strongly typed (that is, not typed ...

  6. Eclipse 插件 —— SVN 的下载与安装

    介绍一下Eclipse 安装 SVN 插件的方法. 第一步:下载资源文件 打开网址 http://subclipse.tigris.org/ ,点击[Download and Install]标签页, ...

  7. 如何把双引号包含到echo命令的字符串中

    初涉s h e l l的用户常常会遇到的一个问题就是如何把双引号包含到e c h o命令的字符串中.引号是一个特殊字符,所以必须要使用反斜杠\来使s h e l l忽略它的特殊含义.假设你希望使用e ...

  8. BZOJ 1502 月下柠檬树(simpson积分)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1502 题意:给出如下一棵分层的树,给出每层的高度和每个面的半径.光线是平行的,与地面夹角 ...

  9. 《OD学Sqoop》数据转换工具Sqoop

    一. 第二阶段课程回顾 hadoop 2.x HDFS YARN MapReduce Zookeeper Hive 二.大数据协作框架 对日志类型的海量数据进行分析 hdfs mapreduce/hi ...

  10. grunt <% %>模板和使用配置文件

        使用<% %>分隔符指定的模板会在任务从它们的配置中读取相应的数据时将自动扩展扫描.模板会被递归的展开,直到配置中不再存在遗留的模板相关的信息(与模板匹配的).    整个配置对象 ...