注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Koala++'s blog

计算广告学 RTB

 
 
 

日志

 
 

Nutch 1.0 源代码分析[7] Fetcher(2)   

2010-03-24 18:41:37|  分类: Nutch |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

         FetcherThread是分析的重点,它继承自Thread,把它的run函数拆开来看:

         第一部分:

activeThreads.incrementAndGet(); // count threads

 

    FetchItem fit = null;

    try {

       while (true) {

           fit = fetchQueues.getFetchItem();

           if (fit == null) {

              if (feeder.isAlive() || fetchQueues.getTotalSize() > 0) {

                  // spin-wait.

                  spinWaiting.incrementAndGet();

                  try {

                     Thread.sleep(500);

                  } catch (Exception e) {

                  }

                  spinWaiting.decrementAndGet();

                  continue;

              } else {

                  // all done, finish this thread

                  return;

              }

           }

         activeThread是增加活动线程的计数,下面的while循环中,fit是一个要抓取的项,这里如果返回的是null,但这并不表明没有可抓取的项了,因为getFetchItem是一个synchronized函数。从feederfetchQueues判断还有没有要抓取的了,如果有,就睡一会再get,如果没有了就结束线程。

         再下来第二部分,页面抓取的一部分:

// fetch the page

redirecting = false;

redirectCount = 0;

do {

 // 有关抓取的内容

} while (redirecting && (redirectCount < maxRedirect));

         Do/while循环退出的条件是,或不是redirecting,或是大于了maxRedirect次数,redirecting就是重定向。

redirecting = false;

Protocol protocol = this.protocolFactory

       .getProtocol(fit.url.toString());

RobotRules rules = protocol.getRobotRules(fit.url,fit.datum);

if (!rules.isAllowed(fit.u)) {

    // unblock

    fetchQueues.finishFetchItem(fit, true);

    output(fit.url, fit.datum, null,

           ProtocolStatus.STATUS_ROBOTS_DENIED,

           CrawlDatum.STATUS_FETCH_GONE);

    continue;

}

if (rules.getCrawlDelay() > 0) {

    if (rules.getCrawlDelay() > maxCrawlDelay) {

       // unblock

       fetchQueues.finishFetchItem(fit, true);

       output( fit.url, fit.datum, null,

              ProtocolStatus.STATUS_ROBOTS_DENIED,

              CrawlDatum.STATUS_FETCH_GONE);

       continue;

    } else {

       FetchItemQueue fiq = fetchQueues

              .getFetchItemQueue(fit.queueID);

       fiq.crawlDelay = rules.getCrawlDelay();

    }

}

         这里从url字符串中得到相应的Protocol接口的实现的对象,并得到RobotRules对象。用它来判断url是否合法,如果不合法,就结束抓取,crawl delay就是爬虫两次访问的时间间隔,如果网站不支持maxCrawlDelay这么快的查询,也deny

ProtocolOutput output = protocol.getProtocolOutput(

       fit.url, fit.datum);

ProtocolStatus status = output.getStatus();

Content content = output.getContent();

ParseStatus pstatus = null;

// unblock queue

fetchQueues.finishFetchItem(fit);

 

String urlString = fit.url.toString();

 

switch (status.getCode()) {

case ProtocolStatus.WOULDBLOCK:

    break;

 

case ProtocolStatus.SUCCESS:

    break;

case XXXXXXXXXXXXX:

    break;

}

         ProtocolOutput有两个成员变量:ContentProtocolStatus

Content中比较重要的变量有:

private String url;

private String base;

private byte[] content;

private String contentType;

private Properties metadata;

         url是原始的url字符串,base是转换为URL后再toString()得到的字符串,contentType 说内网页类型,metadata元数据:meta标签是内嵌在你网页中的特殊html标签,包含着你有关于你网页的一些隐藏信息。Meat标签的作用是向搜索引擎解释你的网页是有关哪方面信息的。

         比如对于http://quweiprotoss.blog.163.com/这个网址:

url为:http://quweiprotoss.blog.163.com/

         base为:http://quweiprotoss.blog.163.com/

         contentType为:text/html;charset=gbk

         metadata为:{Cache-Control=no-cache, Server=nginx, Content-Encoding=gzip, Date=Tue, 23 Feb 2010 08:58:13 GMT, Pragma=no-cache, Vary=Host,User-Agent,Accept-Encoding, Set-Cookie=JSESSIONID=6443124A26B8A59B6E5B5C65DDEF45A7.app-58-8010; Path=/, Expires=Thu, 01 Jan 1970 00:00:00 GMT, Content-Type=text/html;charset=gbk, Connection=close}

         content为:

<?xml version="1.0" encoding="UTF-8"?>

<html>

  <head>

    <title>Koala++&apos;s blog - quweiprotoss - 网易博客</title>

    <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>

    <meta name="Author" content="quweiprotoss, quweiprotoss"/>

    <meta name="Keywords" content="Koala++&amp;apos;s blog, quweiprotoss, quweiprotoss, 网易博客, 网易, blog"/>

    <meta name="Description" content=" Query分析, quweiprotoss的网易博客"/>

         转过去看output的内容,先看前一部分:

datum.setStatus(status);

datum.setFetchTime(System.currentTimeMillis());

datum.getMetaData().put(Nutch.WRITABLE_PROTO_STATUS_KEY,

           pstatus);

 

ParseResult parseResult = null;

if (content != null) {

    try {

       scfilters.passScoreBeforeParsing(key, datum, content);

    }

    /*

     * Note: Fetcher will only follow meta-redirects coming from the

     * original URL.

     */

    if (parsing && status == CrawlDatum.STATUS_FETCH_SUCCESS) {

       try {

           parseResult = this.parseUtil.parse(content);

       }

    }

}

         datum中设置状态,协议状态,这里scfilters是在页面分析前对一个url的权重得分计算,如果要解析就用parseUtil去解析,得到parseResult

output.collect(key, new NutchWritable(datum));

if (content != null && storingContent)

    output.collect(key, new NutchWritable(content));

         keyurlvalue是爬取的有关信息,如果保存页面,就保存。

for (Entry<Text, Parse> entry : parseResult) {

    Text url = entry.getKey();

    Parse parse = entry.getValue();

    ParseStatus parseStatus = parse.getData().getStatus();

 

    // Calculate page signature. For non-parsing fetchers

    // this will be done in ParseSegment

    byte[] signature = SignatureFactory.getSignature(

           getConf()).calculate(content, parse);

    // Ensure segment name and score are in parseData

    // metadata

    parse.getData().getContentMeta().set(

           Nutch.SEGMENT_NAME_KEY, segmentName);

    parse.getData().getContentMeta().set(

           Nutch.SIGNATURE_KEY,

           StringUtil.toHexString(signature));

    // Pass fetch time to content meta

    parse.getData().getContentMeta().set(

           Nutch.FETCH_TIME_KEY,

           Long.toString(datum.getFetchTime()));

    if (url.equals(key))

       datum.setSignature(signature);

    try {

       scfilters.passScoreAfterParsing(url, content, parse);

    }

    output.collect(url, new NutchWritable(new ParseImpl(

           new ParseText(parse.getText()),

           parse.getData(), parse.isCanonical())));

}

         这里循环处理解析后的数据,比如url为:http://vip.163.com/hd/shangdao/index.htm,则parse.getData为:

Version: 5

Status: success(1,0)

Title: 得商道,握天下! - 网易VIP尊贵邮

Outlinks: 30

  outlink: toUrl: http://vip.163.com/hd/shangdao/;this.style.color= anchor:

  outlink: toUrl: http://vip.163.com/hd/shangdao/css/style.css anchor:

  outlink: toUrl: http://vip.163.com/hd/shangdao/js/base.js anchor:

  outlink: toUrl: http://vip.163.com/hd/shangdao/index.htm anchor:

  outlink: toUrl: http://vip.163.com/hd/shangdao/img/tbanner.jpg anchor:

  outlink: toUrl: http://vip.163.com/hd/shangdao/p1.htm anchor: 经济 商贸地图 浓缩展现全球经贸生态 全球股市 黄金原油行情实时查询 汇率换算 轻松贸易

parse.getText为:

得商道,握天下! - 网易VIP尊贵邮 经济 商贸地图 浓缩展现全球经贸生态 全球股市 黄金原油行情实时查询 汇率换算 轻松贸易 商务 商贸应用文 写作更轻松 国际礼仪无所不知 各国

Signature默认用的是MD5Signature,它是页面签名的默认实现,它对页面原始的二进制内容求MD5值,如果没有内容,它计算页面URLMD5值。它就是用于区分网页的,这里就暂时跳过,重点在passScoreAfterParsing

         Fetcher中有一行代码是:

job.setOutputFormat(FetcherOutputFormat.class);

         写成入相应的文件。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  评论这张
 
阅读(2287)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017