c httpclient抓取网页(修改heritrix的默认抓取策略()的抓取算法)
优采云 发布时间: 2022-03-28 02:11c httpclient抓取网页(修改heritrix的默认抓取策略()的抓取算法)
一种。首先修改heritrix的默认爬取策略
Heritrix默认的抓取策略是HostnameQueueAssignmentPolicy,该策略以hostname为key,所以一个域名下的所有连接都会放在同一个线程中,这样会导致抓取时一般只有一个线程运行(一般我们抓取特定 网站 上的内容)。这种方法可以很大程度上解决广域网中取信息时队列的键值问题。但是,单个 网站 网络抓取存在很大问题。以新浪的新闻页面为例,大部分的URL来自新浪网站内部,所以如果使用HostnameQueueAssignmentPolicy,会造成很长的队列。在 Heritrix 中,当线程从队列中获取 URL 链接时,它总是从队列的头部获取第一个链接。在那之后,从中获取链接的队列将进入阻塞状态,直到链接被处理。之后,它将从阻塞状态中恢复。如果使用HostnameQueueAssignmentPolicy策略来处理抓取一个网站的内容的情况,很有可能只有一个线程在工作,而所有其他线程都在等待。这是因为拥有绝大多数 URL 链接的队列将几乎永远被阻塞,因此其他线程根本无法获取 URL,在这种情况下,抓取工作将进入一种类似睡眠的状态。而所有其他线程都在等待。这是因为拥有绝大多数 URL 链接的队列将几乎永远被阻塞,因此其他线程根本无法获取 URL,在这种情况下,抓取工作将进入一种类似睡眠的状态。而所有其他线程都在等待。这是因为拥有绝大多数 URL 链接的队列将几乎永远被阻塞,因此其他线程根本无法获取 URL,在这种情况下,抓取工作将进入一种类似睡眠的状态。
因此,我们需要改变Heritrix的爬取策略,即改变key的生成方式。我们需要使用这个键有效地将所有 URL 散列到不同的队列中,最终减少所有队列长度的方差。,在这种情况下,可以保证工作线程的最大效率。我们需要继承QueueAssignmentPolicy类,重写getClassKey()方法。getClassKey 方法的参数是一个链接对象,ELF Hash 算法可以通过这个链接对象返回一个值,并将其平均分配到各个队列中。更多线程爬取同域名下的网页,爬取速度会大大提高。
ELFHash算法是对字符串进行哈希运算,巧妙地计算出字符的ASCII码值,可以将字符串在哈希表中分布更均匀。
1、以下是ELFHash算法实现的抓取策略:
package org.archive.crawler.frontier;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.httpclient.URIException;
import org.archive.crawler.datamodel.CandidateURI;
import org.archive.crawler.framework.CrawlController;
import org.archive.net.UURI;
import org.archive.net.UURIFactory;
public class ELFHashQueueAssignmentPolicy extends QueueAssignmentPolicy {
private static final Logger logger = Logger.getLogger(ELFHashQueueAssignmentPolicy.class.getName());
/**
* When neat host-based class-key fails us
*/
private static String DEFAULT_CLASS_KEY = "default...";
private static final String DNS = "dns";
public String getClassKey(CrawlController controller, CandidateURI cauri) {
String scheme = cauri.getUURI().getScheme();
String candidate = null;
try {
if (scheme.equals(DNS)){
if (cauri.getVia() != null) {
// Special handling for DNS: treat as being
// of the same class as the triggering URI.
// When a URI includes a port, this ensures
// the DNS lookup goes atop the host:port
// queue that triggered it, rather than
// some other host queue
UURI viaUuri = UURIFactory.getInstance(cauri.flattenVia());
candidate = viaUuri.getAuthorityMinusUserinfo();
// adopt scheme of triggering URI
scheme = viaUuri.getScheme();
} else {
candidate= cauri.getUURI().getReferencedHost();
}
} else {
// 注释掉原来的
// candidate = cauri.getUURI().getAuthorityMinusUserinfo();
// 使用ELFHash算法
String uri = cauri.getUURI().toString();
long hash = ELFHash(uri);
candidate = Long.toString(hash % 100); // 取模 100,Heritrix默认开100个线程,对应100个不同的URI处理队列
}
if(candidate == null || candidate.length() == 0) {
candidate = DEFAULT_CLASS_KEY;
}
} catch (URIException e) {
logger.log(Level.INFO,
"unable to extract class key; using default", e);
candidate = DEFAULT_CLASS_KEY;
}
if (scheme != null && scheme.equals(UURIFactory.HTTPS)) {
// If https and no port specified, add default https port to
// distinguish https from http server without a port.
if (!candidate.matches(".+:[0-9]+")) {
candidate += UURIFactory.HTTPS_PORT;
}
}
// Ensure classKeys are safe as filenames on NTFS
return candidate.replace(':','#');
}
public long ELFHash(String str) {
long hash = 0;
long x = 0;
for (int i = 0; i < str.length(); i++) {
hash = (hash > 24);
hash &= ~x;
}
}
return (hash & 0x7FFFFFFF);
}
}
2、在 org.archive.crawler.frontier.AbstractFrontier 类中查找“HostnameQueueAssignmentPolicy”关键字,大约第 293 行,注释掉更改,然后添加我们的 ELFHashQueueAssignmentPolicy,如下(蓝色字体行):
// Read the list of permissible choices from heritrix.properties.
// Its a list of space- or comma-separated values.
String queueStr = System.getProperty(AbstractFrontier.class.getName() +
"." + ATTR_QUEUE_ASSIGNMENT_POLICY,
// HostnameQueueAssignmentPolicy.class.getName() + " " +
ELFHashQueueAssignmentPolicy.class.getName() + " " +
IPQueueAssignmentPolicy.class.getName() + " " +
BucketQueueAssignmentPolicy.class.getName() + " " +
SurtAuthorityQueueAssignmentPolicy.class.getName() + " " +
TopmostAssignedSurtQueueAssignmentPolicy.class.getName());
Pattern p = Pattern.compile("\\s*,\\s*|\\s+");
String [] queues = p.split(queueStr);
3、修改heritrix.properties文件中的配置,在文件中查找“HostnameQueueAssignmentPolicy”关键字,15左右两行9、160,复制后将这两行注释掉,粘贴到下面, 将这两行中的“HostnameQueueAssignmentPolicy”替换为“ELFHashQueueAssignmentPolicy”,如下(蓝色字体):
#org.archive.crawler.frontier.AbstractFrontier.queue-assignment-policy = 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.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.AbstractFrontier.queue-assignment-policy = org.archive.crawler.frontier.ELFHashQueueAssignmentPolicy org.archive.crawler.frontier.IPQueueAssignmentPolicy org.archive.crawler.frontier.BucketQueueAssignmentPolicy org.archive.crawler.frontier.SurtAuthorityQueueAssignmentPolicy org.archive.crawler.frontier.TopmostAssignedSurtQueueAssignmentPolicy
org.archive.crawler.frontier.ELFHashQueueAssignmentPolicy org.archive.crawler.frontier.IPQueueAssignmentPolicy org.archive.crawler.frontier.BucketQueueAssignmentPolicy org.archive.crawler.frontier.SurtAuthorityQueueAssignmentPolicy org.archive.crawler.frontier.TopmostAssignedSurtQueueAssignmentPolicy
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
下面我们分别使用这两种抓取策略来创建抓取任务并做个对比:
下图是使用 HostnameQueueAssignmentPolicy 抓取策略创建的任务的状态图:
下图是使用 ELFHashQueueAssignmentPolicy 抓取策略创建的任务的状态图:
从上面两张图可以看出,同时在活跃线程数和fetches总大小上,ELFHashQueueAssignmentPolicy远高于HostnameQueueAssignmentPolicy。
注意:当使用 ELFHashQueueAssignmentPolicy 爬取策略时,爬取可能会停止。检查任务的 crawl.log 日志。URL后跟“robots.txt”,如:“”。这是因为Heritrix是一个完整的遵守“robots.txt”协议的网络爬虫,如果一个网站声明了他们不想被机器人访问的部分文件,Heritrix不会爬取那些内容。可以去掉robots.txt的限制,应该不会出现这种现象。
湾。取消rebots.txt的限制。
关于rebots.txt协议的取消,可以参考另一篇文章文章:
C。抓取指定网页内容
Heritrix的Extractors用于解析当前服务器返回的内容,提取页面中的URL,放入提取队列。因为它会爬取网页中的所有链接,但是有些链接不是我们想要的,比如图片链接、pdf文档等,这些链接需要过滤掉,我们可以创建自己的Extractor来爬取特定的网页内容。如下,是一个自定义的抓取搜狐新闻的Extractor:
<p>package org.archive.crawler.extractor;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.archive.crawler.datamodel.CrawlURI;
import org.archive.io.ReplayCharSequence;
import org.archive.util.HttpRecorder;
public class ExtractorSohu extends Extractor {
private static final long serialVersionUID = -7914995152462902519L;
public ExtractorSohu(String name, String description) {
super(name, description);
}
public ExtractorSohu(String name) {
super(name, "sohu news extractor");
}
// http://news.sohu.com/20131020/n388534488.shtml
private static final String A_HERF = "