摘自http://blog.sina.com.cn/s/blog_6cc084c90100nf39.html

---------------------------------------------------------------------------------

一.利用ELFHash策略多线程抓取网页

这些天看了其它小组的博客,发现大家用Heritrix抓取所花的时间都比较长,基本都要花上数天的时间才能抓完,名副其实的爬虫…之所以这么慢,一个重要的原因是heritrix在抓取时一般只运行了一个线程。在网上查找原因,得知这是因为在默认的情况下,Heritrix使用HostnameQueueAssignmentPolicy来产生key值,而这个策略是用hostname作为key值的,因此一个域名下的所有链接都会被放到同一个线程中去。如果对Heritrix分配URI时的策略进行改进,利用ELF hash算法把url尽量平均分部到各个队列中去,就能够用较多的线程同时抓取一个域名下的网页,速度将得到大大的提高。

具体的做法如下:

1.在org.archive.crawler.frontier下新建一个ELFHashQueueAssignmentPolicy类,这个类要注意继承自 QueueAssignmentPolicy。

2.在该类下编写代码如下:

 public class ELFHashQueueAssignmentPolicy extends QueueAssignmentPolicy{
@Override
public String getClassKey(CrawlController controller, CandidateURI cauri) {
return this.ELFHash(cauri.getUURI().toString(), 50) + "";
} public int ELFHash(String str, int number) {
int hash = 0;
long x = 0l;
char[] array = str.toCharArray();
for (int i = 0; i < array.length; i++) {
hash = (hash << 4) + array[i];
if ((x = (hash & 0xF0000000L)) != 0) {
hash ^= (x >> 24);
hash &= ~x;
}
}
int result = (hash & 0x7FFFFFFF) % number;
return result;
}
}

3.  修改AbstractFrontier 类的AbstractFrontier方法 :

关键代码段是:

String queueStr = System.getProperty(AbstractFrontier.class.getName() +
                 "." + ATTR_QUEUE_ASSIGNMENT_POLICY,
                  ELFHashQueueAssignmentPolicy.class.getName() + " " +

HostnameQueueAssignmentPolicy.class.getName() + " " +

IPQueueAssignmentPolicy.class.getName() + " " +

BucketQueueAssignmentPolicy.class.getName() + " " +

SurtAuthorityQueueAssignmentPolicy.class.getName());

Pattern p = Pattern.compile("\\s*,\\s*|\\s+");

String [] queues = p.split(queueStr);

其中红色部分是新加的代码。

4.  修改heritrix.properties 中的配置

#############################################################################
        # F R O N T I E R                                                          
        #############################################################################

# List here all queue assignment policies you'd have show as a
        # queue-assignment-policy choice in AbstractFrontier derived Frontiers
        # (e.g. BdbFrontier).
        org.archive.crawler.frontier.AbstractFrontier.queue-assignment-policy = \

org.archive.crawler.frontier.ELFHashQueueAssignmentPolicy \

org.archive.crawler.frontier.HostnameQueueAssignmentPolicy \

org.archive.crawler.frontier.IPQueueAssignmentPolicy \

org.archive.crawler.frontier.BucketQueueAssignmentPolicy \

org.archive.crawler.frontier.SurtAuthorityQueueAssignmentPolicy \

org.archive.crawler.frontier.TopmostAssignedSurtQueueAssignmentPolicy

org.archive.crawler.frontier.BdbFrontier.level = INFO

红色部分为新加部分。

添加代码后运行的结果如下图,可见Heritrix已经在开50个线程同时抓取网页。

抓取速度得到了很大的提高,1.4G的网页8个多小时就抓好了。在Hosts栏里显示,只抓取了ccer.pku.edn.cn域名下的网页。

</:O:P>

一些分析:

1)添加的ELFHash算法程序并不算很复杂。ELFhash算法的基本思想是:将一个字符串的数组中的每个元素依次按前四位与上一个元素的低四位相与,组成一个长整形,如果长整的高四位大于零,那么就将它折回再与长整的低四位相异或,这样最后得到的长整对HASH表长取余,得到在HASH中的位置。

2)ELFHash函数将输入的字符串进行哈希计算,输出算出的整数型哈希值。getClassKey函数中调用了ELFHash函数计算出哈希值,转换为字符串型返回上一层。之所以取模100是因为一般情况下Heritrix开100个线程,对应100个不同的URI处理队列。

3)  QueueAssignmentPolicy类源程序里的说明:

* Establishes a mapping from CrawlURIs to String keys (queue names).

* Get the String key (name) of the queue to which the

* CrawlURI should be assigned.

*

* Note that changes to the CrawlURI, or its associated

* components (such as CrawlServer), may change its queue

* assignment.

可知该类建立抓取到的URI和抓取队列名之间的映射。这个类是个抽象类,不同的策略由不同的子类实现,如根据域名、IP等。

4)AbstractFrontier类是调度器基本实现类,是一个非常复杂的类,没有仔细研究。这里加在里面的程序作用大概是将ELFHashQueueAssignmentPolicy这个策略加入到运行时所使用的URI分配策略中。在heritrix.properties中的修改也同样为这个目的。

5)由上可见使用这个策略后,速度有了非常大的提高。但抓下来的1.4G数据相比之前抓下来的有点小,大概是max-retries值设置得太低(原来是30,改为5),导致不少东西没有抓下来。

二.只抓取HTML对象

由上面的图可以知道抓取的内容中有一些不需要用到的文件类型,比如pdf,jpeg等等。如何用Heritrix只抓特定的对象,比如只抓HTML型的。Heritrix的官方文档”Heritrix User Manual”中A.3节给出了一个解决方案:

1)You would first need to create a job with the single seed http://foo.org/bar/. You'll need to add the MirrorWriterProcessor on the Modules screen and delete the ARCWriterProcessor. This will store your files in a directory structure that matches the crawled URIs, and the files will be stored in the crawl job's mirror directory.

2)Your job should use the DecidingScope with the following set of DecideRules:

RejectDecideRule

SurtPrefixedDecideRule

TooManyHopsDecideRule

PathologicalPathDecideRule

TooManyPathSegmentsDecideRule

NotMatchesFilePatternDecideRule

PrerequisiteAcceptDecideRule

We are using the NotMatchesFilePatternDecideRule so we can eliminate crawling any URIs that don't end with .html. It's important that this DecideRule be placed immediately before PrerequisiteAcceptDecideRule; otherwise the DNS and robots.txt prerequisites will be rejected since they won't match the regexp.

3)On the Setting screen, you'll want to set the following for the NotMatchesFilePatternDecideRule:

decision: REJECT

use-preset-pattern: CUSTOM

regexp: .*(/|\.html)$

根据需要,将正则表达式进行修改以满足需要,在这里更改为:

(.*(/|\.(html|htm|xml|asp))$)|(.*\.asp\?.*)
    抓取的效果如下图所示:

三.取消Robots.txt的限制

Robots.txt是一种专门用于搜索引擎网络爬虫的文件,当构造一个网站时,如果作者希望该网站的内容被搜索引擎收录,就可以在网站中创建一个纯文本文件robots.txt,在这个文件中,声明该网站不想被robot访问的部分。这样,该网站的部分或全部内容就可以不被搜索引擎收录了,或者指定搜索引擎只收录指定的内容。因为大部分的网站并不会放置一个robots.txt文件以供搜索引擎读取,所以 Heritrix爬虫在抓取网页时会花费过多的时间去判断该Robots.txt文件是否存在,从而增加了抓取时间。好在这个协议本身是一种附加协议,完全可以不遵守。

在Heritrix中,对robots.txt文件的处理是处于PreconditionEnforcer这个Processor中的。PreconditionEnforcer是一个Prefetcher,当处理时,总是需要考虑一下当前这个链接是否有什么先决条件要先被满足的,而对robots.txt的访问则正好是其中之一。在PreconditionEnforcer中,有一个private类型的函数,函数声明为: private boolean considerRobotsPreconditions(CrawlURI curi)  。该函数的含义为:在进行对参数所表示的链接的抓取前,看一下是否存在一个由robots.txt所决定的先决条件。该函数返回true时的含义为需要考虑robots.txt文件,返回false时则表示不需要考虑robots.txt文件,可以继续将链接传递给后面的处理器。所以,最简单的修改办法就是将这个方法整个注释掉,只返回一个false值。

网上声称使用这种办法可以提高抓取速度一半以上,由于抓取所花时间比较多,没有进行对比比较。以上的抓取都是在去除robots.txt情况下进行的。

[转载]Heritrix 提高效率的若干方法的更多相关文章

  1. PhpStorm提高效率的使用方法及设置

    快捷键: CTRL + D  复制当前行到下一行 或 复制选中内容到选中内容之后 CTRL + Y  删除当前行或选中内容所涉及的行 CTRL + R  替换 CTRL + F  查找 ALT + 上 ...

  2. PhpStorm提高效率的使用方法及设置(快捷键)

    原文链接:https://my.oschina.net/chunto/blog/262954 快捷键: CTRL + D  复制当前行到下一行 或 复制选中内容到选中内容之后 CTRL + Y  删除 ...

  3. sql的简单提高效率方法

    少用in操作(效率极差),尽量用表关联代替 select要指定列,不要*(*会读入所有数据,而指定列则只提取涉及的列,减少io) 尽量有where(减少读取量),where操作列尽量有索引(加快查询) ...

  4. [转载]要提高SQL查询效率where语句条件的先后次序应如何写

    出处:https://www.cnblogs.com/exe19/p/5786806.html 我们要做到不但会写SQL,还要做到写出性能优良的SQL语句. (1)选择最有效率的表名顺序(只在基于规则 ...

  5. IT之快速提高效率的方法与思考

    前言 文章也没什么很高深的问题,大概花个5分钟能看完.是一些大家都知道的道理,作为提醒与总结. 关于提高方面的内容,一般都有个人的方法,但大致都一致.可分为几个步骤. 框架.工具使用相关 使用框架.工 ...

  6. Atitit.研发管理--提升效率--软件开发方法DSM总结o99

    Atitit.研发管理--提升效率--软件开发方法DSM总结o99 1. 什么是DSM? 1 2. DSM使用的语言DSL 2 3. 模型的优点 2 4. DSM 跟与MDA区别 2 5. MDA的实 ...

  7. 批处理文件(.bat)并行Arcpy脚本提高效率的思路

    Arcpy提供数据处理的方便接口,但一个Arcpy脚本通常只运行于一个核上.现在电脑通常是多核乃至多处理器,如果能将任务分解为可同时进行的若干任务,便可通过并行充分利用电脑性能. 折腾了python并 ...

  8. Oracle多表连接,提高效率,性能优化 (转)

    执行路径:ORACLE的这个功能大大地提高了SQL的执行性能并节省了内存的使用:我们发现,单表数据的统计比多表统计的速度完全是两个概念.单表统计可能只要0.02秒,但是2张表联合统计就可能要几十表了. ...

  9. SQL Server 百万级数据提高查询速度的方法

    1.应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描. 2.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉 ...

随机推荐

  1. Win32应用程序的基本结构

    0 引言 Win32 API是用于创建 Windows 应用程序的应用程序编程接口.通常情况下,一个Win32应用包含一下几个部分: 1)    应用程序入口: 2)    注册窗口类: 3)    ...

  2. leetcode remove Nth Node from End python

    # Definition for singly-linked list. # class ListNode(object): # def __init__(self, x): # self.val = ...

  3. jQuery1.9.1针对checkbox的调整

    在jquery 1.8.x中的版本,我们对于checkbox的选中与不选中操作如下: 判断是否选中 $('#checkbox').prop('checked') 设置选中与不选中状态: $('#che ...

  4. jquery结合Highcharts插件实现动态数据仪表盘图形化显示效果

    仪表盘显示效果如图: 方法一效果图: 方法二效果图(插件版本4.0.1): ​ js代码如下: $(function(){ //方法一: var chart = new Highcharts.Char ...

  5. js previousSibling兼容使用方法

    使用previousSibling的时候发现当前元素跟上一个元素之间有空格就不获取不到对象, 查资料才知道除了ie外js的previousSibling获取的对象包括空格! 兼容方法如下: funct ...

  6. 【Howie玩docker】-Docker常用命令操作

    attach     附加到一个运行的容器上面       --no-stdin=false Do not attach stdin       --sig-proxy=true Proxify al ...

  7. 3D空间坐标系转换复习

    模型坐标系:ModelSpace     即模型本身为中心  模型本身自己 世界坐标系:WorldSpace    世界坐标系   整个世界 视角坐标系: ViewSpace       眼睛看到的范 ...

  8. tiny4412学习笔记-将uboot、zImage、文件系统烧到emmc中

    1.首先还是要将u-boot写入SD卡中从SD卡启动. 使用读卡器将SD插入电脑中,使用umount卸载u盘, fdisk -l显示其挂载点为 /dev/sdb1 切换到/home/bunfly/im ...

  9. 【java】静态方法声明与调用习题

    public class dengd { static int getTt(int table[]) { for(int b=0; b<table.length;b++) { System.ou ...

  10. Oracle EBS-SQL (BOM-6):检查物料失效但BOM中未失效的数据.sql

    select msi.segment1                   装配件编码 , msi.description                  装配件描述 , msi.item_type ...