`

网络信息体系结构作业1

阅读更多
要求如下:

内容:crawler和graph link analysis
1。heritrix系统使用 要求:配置、安装Heritrix,抓取指定的网站: http://www.ccer.pku.edu.cn/
2。heritrix系统代码分析 要求:按Week2的web crawler系统结构,寻找Heritrix系统里面的crawler的下面两个部分:
     isUrlVisited,politeness
    分析它们的实现技术。
3。搜集web数据的graph link analysis 要求:回答以下问题,并给出方法的说明
     这个网站有多少网页?
    入度、出度分布情况如何?
    top 10的最重要页面是哪些?
提交:一个简短的技术报告文档,报告上述作业完成情况。

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


1。Heritrix的配置
参考我的博客http://hanyuanbo.iteye.com/blog/777451
2。对isURLVisited和politeness如下分析:

isUrlVisited
isURLVisited主要用来处理当一个链接要进入等待队列时判断该链接是否已经被抓取过,如果已经抓取过则不进入被处理队列,否则进入。
这就要从分析存储已抓取url的结构说起。Heritrix在内部使用了Berkeley DB(Database)。Berkeley DB就是一个HashTable,它能够按“key/value”方式来保存数据。它是一套开放源代码的嵌入式数据库,为应用程序提供可伸缩的、高性能的、有事务保护功能的数据管理服务。Berkeley DB就是一个Hash Table,它能够按“key/value”方式来保存数据。使用Berkeley DB时,数据库和应用程序在相同的地址空间中运行,所以数据库操作不需要进程间的通讯。另外,Berkeley DB中的所有操作都使用一组API接口。因此,不需要对某种查询语言(比如SQL)进行解析,也不用生成执行计划,这就大大提高了运行效率。解决了多线程访问、超大容量的问题。
Heritrix中涉及存储url的主要的类分布在org.archive.crawler.util包下,之间的继承关系如下图:



用户可以在创建一个爬取任务时选择其中的一种过滤器,默认是BdbUriUniqFilter。而且这也是在Heritrix抓取过程中使用的唯一一种方式。

这里存储已经处理过的url的数据结构是Berkeley Database,叫做alreadySeen。
protected transient Database alreadySeen = null;

为了节省存储空间,alreadySeenUrl中存储的并不是url,而是url的fingerprint(64位)。为了不破坏url的局部性,分别对url的主机名和整个url计算fingerprint,然后把24位的主机名fingerprint和40位的url的fingerprint连接起来得到最后的64位的fingerprint。计算fingerprint是在createKey函数中实现。代码如下:
  
 /**
     * Create fingerprint.
     * Pubic access so test code can access createKey.
     * @param uri URI to fingerprint.
     * @return Fingerprint of passed <code>url</code>.
     */
    public static long createKey(CharSequence uri) {
        String url = uri.toString();
        int index = url.indexOf(COLON_SLASH_SLASH);
        if (index > 0) {
            index = url.indexOf('/', index + COLON_SLASH_SLASH.length());
        }
        CharSequence hostPlusScheme = (index == -1)? url: url.subSequence(0, index);
        long tmp = FPGenerator.std24.fp(hostPlusScheme);
        return tmp | (FPGenerator.std40.fp(url) >>> 24);
    }

setAdd函数把uri加入到数据库中,如果已经存在,则返回false,否则返回true。关键代码如下:(根据自己的理解加入了注释)
   
protected boolean setAdd(CharSequence uri) {
        DatabaseEntry key = new DatabaseEntry();
        LongBinding.longToEntry(createKey(uri), key);//将uri的fingerprint从long类型转换成DatabaseEntry类型,以便于Database进行存储。
        long started = 0;
        
        OperationStatus status = null;
        try {
            if (logger.isLoggable(Level.INFO)) {
                started = System.currentTimeMillis();
            }
            status = alreadySeen.putNoOverwrite(null, key, ZERO_LENGTH_ENTRY);//检查是否已经被抓取过,并返回状态给status
            if (logger.isLoggable(Level.INFO)) {
                aggregatedLookupTime +=
                    (System.currentTimeMillis() - started);
            }
        } catch (DatabaseException e) {
            logger.severe(e.getMessage());
        }
        if (status == OperationStatus.SUCCESS) {
            count++;
            if (logger.isLoggable(Level.INFO)) {
                final int logAt = 10000;
                if (count > 0 && ((count % logAt) == 0)) {
                    logger.info("Average lookup " +
                        (aggregatedLookupTime / logAt) + "ms.");
                    aggregatedLookupTime = 0;
                }
            }
        }
        if(status == OperationStatus.KEYEXIST) {//是否已经探测过
            return false;
        } else {
            return true;
        }
    }


politeness
(1) 每个时间只有一个面向服务器的连接(one connection at a time)
Heritrix的礼貌性主要在Frontier中实现:一次对一个服务器只开一个链接,并且保证uri按一定速率处理,从而不会给被爬取的服务器造成负担。
爬虫采用广度优先遍历,使用FIFO的队列来存储待爬取的URL。因为网页的局部性,队列中相邻的URL很可能是相同主机名的,这样爬取会给服务器造成很大负担。如果用很多队列来存放URL,每个队列中URL的主机名相同,同一时间里,只允许队列中一个URL被爬取,就能避免上述问题了。

heritrix中主机名相同的URL队列是用WorkQueue来实现的,一个WorkQueue就是一个具有相同主机名的队列。在Heritrix中,还有其他的队列,代码如下:(在org.archive.crawler.frontier.WorkQueueFrontier.java中)

/** All known queues.
     */
    protected transient ObjectIdentityCache<String,WorkQueue> allQueues = null; 
    // of classKey -> ClassKeyQueue



  /**
     * Set up the various queues-of-queues used by the frontier. Override
     * in implementing subclasses to reduce or eliminate risk of queues
     * growing without bound. 
     */
    protected void initQueuesOfQueues() {
        // small risk of OutOfMemoryError: if 'hold-queues' is false,
        // readyClassQueues may grow in size without bound
        readyClassQueues = new LinkedBlockingQueue<String>();
        // risk of OutOfMemoryError: in large crawls, 
        // inactiveQueues may grow in size without bound
        inactiveQueues = new LinkedBlockingQueue<String>();
        // risk of OutOfMemoryError: in large crawls with queue max-budgets, 
        // inactiveQueues may grow in size without bound
        retiredQueues = new LinkedBlockingQueue<String>();
        // small risk of OutOfMemoryError: in large crawls with many 
        // unresponsive queues, an unbounded number of snoozed queues 
        // may exist
        snoozedClassQueues = Collections.synchronizedSortedSet(new TreeSet<WorkQueue>());
    }


在子类BdbFrontier中的初始化过程如下:
public void initialize(CrawlController c)
    throws FatalConfigurationException, IOException {
        this.controller = c;
        // fill in anything from a checkpoint recovery first (because
        // usual initialization will skip initQueueOfQueues in checkpoint)
        if (c.isCheckpointRecover()) {
            // If a checkpoint recover, copy old values from serialized
            // instance into this Frontier instance. Do it this way because 
            // though its possible to serialize BdbFrontier, its currently not
            // possible to set/remove frontier attribute plugging the
            // deserialized object back into the settings system.
            // The below copying over is error-prone because its easy
            // to miss a value.  Perhaps there's a better way?  Introspection?
            BdbFrontier f = null;
            try {
                f = (BdbFrontier)CheckpointUtils.
                    readObjectFromFile(this.getClass(),
                        c.getCheckpointRecover().getDirectory());
            } catch (FileNotFoundException e) {
                throw new FatalConfigurationException("Failed checkpoint " +
                    "recover: " + e.getMessage());
            } catch (IOException e) {
                throw new FatalConfigurationException("Failed checkpoint " +
                    "recover: " + e.getMessage());
            } catch (ClassNotFoundException e) {
                throw new FatalConfigurationException("Failed checkpoint " +
                    "recover: " + e.getMessage());
            }

            this.nextOrdinal = f.nextOrdinal;
            this.totalProcessedBytes = f.totalProcessedBytes;
            this.liveDisregardedUriCount = f.liveDisregardedUriCount;
            this.liveFailedFetchCount = f.liveFailedFetchCount;
            this.processedBytesAfterLastEmittedURI =
                f.processedBytesAfterLastEmittedURI;
            this.liveQueuedUriCount = f.liveQueuedUriCount;
            this.liveSucceededFetchCount = f.liveSucceededFetchCount;
            this.lastMaxBandwidthKB = f.lastMaxBandwidthKB;
            this.readyClassQueues = f.readyClassQueues;
            this.inactiveQueues = reinit(f.inactiveQueues,"inactiveQueues");//inactiveQueues的初始化
            this.retiredQueues = reinit(f.retiredQueues,"retiredQueues");//retiredQueues的初始化
            this.snoozedClassQueues = f.snoozedClassQueues;//snoozedClassQueues的初始化
            this.inProcessQueues = f.inProcessQueues;
            super.initialize(c);
            wakeQueues();
        } else {
            // perform usual initialization 
            super.initialize(c);
        }
    }


readyClassQueues存储着已经准备好被爬取的队列的key;
inactiveQueues存储着所有非活动状态的url队列的key;
retiredQueues存储着不再激活的url队列的key。
snoozedClassQueues:存储着所有休眠的url队列的key,它们都按唤醒时间排序;

线程返回readyClassQueues和snoozedClassQueues中已经到唤醒时间的队列中第一个url,下载相应的文档,完成之后从队列中移除该url。每爬取到一个url都需要判断应该加入哪个队列中。 首先根据url的主机名判断是否存在该主机名的队列,如果不存在就新建一个队列。然后判断该队列是否在生命周期内,如果不在就设置为在生命周期内。如果队列需要保持不激活状态或者活动队列的数量超过设定的阈值,就把该队列放入inactiveQueues中,否则放在readyClassQueues中。
另外,heritrix还设定了很多参数来限制对服务器的访问频率。如最长等待时间max-delay-ms,默认30秒;重连同一服务器至少等待时间min-delay-ms,默认是3秒,重连同一服务器要等待上次连接间隔的几倍delay-factor,默认是5。

(2) robots.txt
robots.txt称为机器人协议,放在网站的根目录下。在这个文件中声明该网站中不想被robot 访问的部分,或者指定搜索引擎只收录指定的内容。这是一个君子协定,爬虫可以不遵守,但是出于礼貌最好遵守。
heritrix在预处理阶段处理robots.txt。它把针对每个user-agent的allow和disallow封装为一个RobotsDirectives类,整个robots.txt用一个Robotstxt对象来存储。
heritrix处理robots.txt有五种方法,都封装在RobotsHonoringPolicy中。这五种方法分别是:
Classic:遵守robots.txt对当前user-agent的第一部分指令。
Ignore:忽略robots.txt。
Custom:遵守robots.txt中特定操作的指令。
Most-favored:遵守最宽松的指令。
Most-favored-set:给定一些user-agent格式的集合,遵守最宽松的限制。

当策略是Most-favored或Most-favored-set时,可以选择是否伪装成另一个user agent。
RobotsExlusionPolicy类中包含heritrix最终处理robots.txt的方法,disallows用来判断userAgent能否访问某个url。它完全依据用户在新建一个爬虫任务时设置的处理robots.txt的策略来实现。

在源代码中的反应如下:
RobotsDirectives.java
Robotstxt.java
RobotsHonoringPolicy.java
RobotsExclusionPolicy.java包都存放在org.archive.crawler.datamodel包下。而且通过查看源文件即可看到类的注释。分别如下:
/**
 * Represents the directives that apply to a user-agent (or set of
 * user-agents)
 */
public class RobotsDirectives implements Serializable{
...
}

/**
 * Utility class for parsing and representing 'robots.txt' format 
 * directives, into a list of named user-agents and map from user-agents 
 * to RobotsDirectives. 
 */
public class Robotstxt implements Serializable{
...
}

/**
 * RobotsHonoringPolicy represent the strategy used by the crawler 
 * for determining how robots.txt files will be honored. 
 *
 * Five kinds of policies exist:
 * <dl>
 * <dt>classic:</dt>
 *   <dd>obey the first set of robots.txt directives that apply to your 
 *   current user-agent</dd>
 * <dt>ignore:</dt>
 *   <dd>ignore robots.txt directives entirely</dd>
 * <dt>custom:</dt>
 *   <dd>obey a specific operator-entered set of robots.txt directives 
 *   for a given host</dd>
 * <dt>most-favored:</dt>
 *   <dd>obey the most liberal restrictions offered (if *any* crawler is 
 *   allowed to get a page, get it)</dd>
 * <dt>most-favored-set:</dt>
 *   <dd>given some set of user-agent patterns, obey the most liberal 
 *   restriction offered to any</dd>
 * </dl>
 *
 * The two last ones has the opportunity of adopting a different user-agent 
 * to reflect the restrictions we've opted to use.
 *
 */
public class RobotsHonoringPolicy  extends ModuleType{
...
} 

/**
 * RobotsExclusionPolicy represents the actual policy adopted with 
 * respect to a specific remote server, usually constructed from 
 * consulting the robots.txt, if any, the server provided. 
 * 
 * (The similarly named RobotsHonoringPolicy, on the other hand, 
 * describes the strategy used by the crawler to determine to what
 * extent it respects exclusion rules.)
 * 
 * The expiration of policies after a suitable amount of time has
 * elapsed since last fetch is handled outside this class, in 
 * CrawlServer itself. 
 * 
 * TODO: refactor RobotsHonoringPolicy to be a class-per-policy, and 
 * then see if a CrawlServer with a HonoringPolicy and a RobotsTxt
 * makes this mediating class unnecessary. 
 * 
 * @author gojomo
 *
 */
public class RobotsExclusionPolicy implements Serializable{
...
}


3。根据自己抓到的网站的本地mirror文件,进过分析,做出如下代码,来得到答案(可能不太准确,大致结果应该没问题)。
package com.analysis.sishendaili;

import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class StringUtil {

	/**
	 * 根据正则表达式选取一个文件中的所有在<a href ..> 或者 <A href...>中的链接URL地址。
	 * 但是去掉了其中的mailto和javascript的链接,这不是一个url地址
	 * @param content
	 * @return
	 */
	public static Set<String> getURLs(String content){
		Set<String> allURLs = new HashSet<String>();
		String regex = "<[aA] href=\"[^\"]+";//出度的正则表达式
		Matcher matcher = Pattern.compile(regex).matcher(content);
		while(matcher.find()){
			String ahref = matcher.group();
			int index = ahref.indexOf("\"");
			if(index > 0 && !ahref.toLowerCase().contains("mailto") && !ahref.toLowerCase().contains("javascript")){//去掉mailto和javascript的 <a href...>
				String url = ahref.substring(index+1);
				url = StringUtil.trimLastSlash(url);
				allURLs.add(url);
			}
		}
		
		return allURLs;
	}
	
	/**
	 * 为了能够在map中找到相应的url地址,把最后的斜杠去掉。
	 * 因为有的有,有的没有,但却是同一个url。故统一去掉来判断是否是同一个url
	 * @param origin
	 * @return
	 */
	public static String trimLastSlash(String origin){
		int length = origin.length();
		if(origin.endsWith("\\") || origin.endsWith("/")){
			return origin.substring(0, length-1);
		}else{
			return origin;
		}
	}
	
	public static void main(String[] args) {
		String filename = "jobs\\ccer3-20101019015958086\\mirror\\www.ccer.pku.edu.cn\\cn\\facultySecondClassId=207.asp";
		String content = FileUtil.getDiskFileContentInOneLine(filename);
		Set<String> allURLs = getURLs(content);
		System.out.println(allURLs.size());
		for(String url : allURLs){
			System.out.println(url);
		}
	}
}

package com.analysis.sishendaili;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class FileUtil {

	/**
	 * 得到指定文件的内容
	 * @param filename
	 * @return
	 */
	public static String getDiskFileContentInOneLine(String filename) {
		StringBuffer sb = new StringBuffer();
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new FileReader(new File(filename)));
			String line = "";
			while((line = reader.readLine()) != null){
				sb.append(line);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally{
			if(reader != null){
				try {
					reader.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return sb.toString();
	}
	
	public static String getDiskFileContentWithLines(String filename){
		StringBuffer sb = new StringBuffer();
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new FileReader(new File(filename)));
			String line = "";
			while((line = reader.readLine()) != null){
				sb.append(line + "\n");
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally{
			if(reader != null){
				try {
					reader.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return sb.toString();
	}
	
	public static void main(String[] args) {
		String filename = "jobs\\ccer3-20101019015958086\\mirror\\www.ccer.pku.edu.cn\\cn\\facultySecondClassId=207.asp";
		String content = FileUtil.getDiskFileContentInOneLine(filename);
		System.out.println(content);
	}

}

package com.analysis.sishendaili;

public class Convert {
	/**
	 * 将从网页上下载下来的东西,如果是汉字的话会出现乱码。
	 * 使用该函数将其转换为原来的汉字
	 * 编码方式有 utf-8 ISO-8859-1 gb2312 gbk
	 * @param str
	 * @return
	 */
	public static String convert(String str) {
		String result = "";
		try {
			result = new String(str.getBytes("ISO-8859-1"), "gb2312");
		} catch (Exception ex) {
			result = "";
		}
		return result;
	}

	public static void main(String[] args) {
		String msg = "Resultkeyword=2005Äê4ÔÂ19ÈÕУÄÚ˫ѧλ»®¿¨½»·ÑÇé¿ö.asp";
		String result = Convert.convert(msg);
		System.out.println(result);//Resultkeyword=2005年4月19日校内双学位划卡交费情况.asp
		
		msg = "Ñо¿ÉúÐ¿Σº¾­¼Ã³É³¤¹ØÁ¬Ñо¿£¨8.26¸üУ©";
		result = Convert.convert(msg);
		System.out.println(result);
	}
}


package com.analysis.sishendaili;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.PrintStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class Analysis {

	public static String dotASPQues = ".asp?";
	public static String baseDir = "jobs\\ccer3-20101019015958086\\mirror\\www.ccer.pku.edu.cn\\cn\\";

	/**
	 * Heritrix在下载网页的时候,将网页的url进行了处理。
	 * 在url含有以下字符串时,将".asp?"去掉,并在结尾加上了".asp"
	 */
	@SuppressWarnings("serial")
	public static Set<String> items = new HashSet<String>(){{
		this.add("faculty");
		this.add("news");
		this.add("rdlist");
		this.add("ReadNews");
		this.add("readview");
		this.add("Result");
		this.add("review");
		this.add("SecondClass");
		this.add("SmallClass");
		this.add("Special_News");
		this.add("Special");
	}};
	
	
	/**
	 * 这个map中存储的是未处理过的网页 到 处理过的网页 的一一映射
	 * 而且是加入了 http://www.pku.edu.cn/ 和 http://www.pku.edu.cn/cn/ 网页
	 * 处理之后总共有 18901个网页
	 */
	public static Map<String,String> map = new HashMap<String,String>();
	
	public static Map<String,Integer> out = new HashMap<String,Integer>();
	
	public static Map<String,Integer> in = new HashMap<String,Integer>();//初始化in的时候,in中的url为ccer下的所有网页,但是在处理过程中,有一些不是ccer网站下的网页但却是链接到其他的网页的url,这些也被加入到了in中,这也是对于ccer来说重要的url,虽然不是ccer的网页。
	
	public static Map<String,Integer> mostImportant10Pages = new HashMap<String,Integer>();
	
	/**
	 * 得到指定path下的所有符合要求的文件
	 * @param path
	 * @return
	 */
	public static String[] getAllPages(String path){
		File file = new File(path);
		String[] pages = file.list(new FilenameFilter(){
			public boolean accept(File file, String name) {
				return name.endsWith("asp");//发现,以asp结尾的文件是网页
			}
		});
		return pages;
	}
	
	/**
	 * 将由Heritrix下载的url还原回原来的地址
	 * @param url
	 * @return
	 */
	public static String toRightFormat(String url){
		for(String item : items){
			if(url.startsWith(item) && url.contains("=")){
				int index = url.indexOf(item);
				int pos = index + item.length();
				int length = url.length();
				url = url.substring(0, pos) + dotASPQues + url.substring(pos, length - 4);//length-4 减去.asp
				break;
			}
		}
		return url;
	}
	
	/**
	 * 对path目录下的所有网页进行了第一次处理
	 * 因为Heritrix对爬下来的网页的文件名进行了重编辑 所以想要得到入度出度时 需要将其还原为原来的名字
	 * 而且有的是乱码 需要进行下处理
	 * 大概2秒中处理完毕
	 * 这个只运行一次 因为只是为了得到正确格式(即 原格式)的网页名称
	 * @throws Exception
	 */
	public static void processAllPages() throws Exception{
		String path = baseDir;
		System.setOut(new PrintStream(new File("analysis\\allPages.txt")));
		
		String[] pages = Analysis.getAllPages(path);
		for(int i=0;i<pages.length;i++){
			String url = Convert.convert(pages[i]);
			url = toRightFormat(url);
			System.out.println(url);
		}
	}
	
	/**
	 * 得到所有正确的网页URL(绝对 或者相对)
	 * @return
	 */
	public static void initialize2Maps(){
		String path = baseDir;
		String[] pages = Analysis.getAllPages(path);
		for(int i=0;i<pages.length;i++){
			String url = Convert.convert(pages[i]);
			url = toRightFormat(url);
			url = StringUtil.trimLastSlash(url);
			map.put(pages[i],url);
			in.put(url, 0);
		}
	}
	
	/**
	 * 用来得到入度 出度的主要处理函数入口
	 */
	public static void process() throws Exception{
		initialize2Maps();
		for(String file : map.keySet()){
			String key = map.get(file);
			String filename = baseDir + file;
			String content = FileUtil.getDiskFileContentInOneLine(filename);
			if(content != null && !content.trim().equals("")){
				Set<String> allURLs = StringUtil.getURLs(content);
				
				out.put(key, allURLs.size());//出度直接将其加入到out中
				
				for(String url : allURLs){//来更新入度的处理
					if(in.containsKey(url)){
						int du = in.get(url);
						in.put(url, ++du);
					}else{
						in.put(url, 1);
					}
				}
			}
		}
		
		getMostImportant10Pages();
		map_in_out_mostImportant10Pages_toDisk();
	}
	
	/**
	 * 这个是在得到了in.txt之后的处理
	 * 因为得到in.txt需要很长时间,所以之后就直接用这个文件来重处理。
	 * @throws Exception
	 */
	public static void getMostImportant10PagesAfter() throws Exception{
		String filename = "analysis\\in.txt";
		Map<String,Integer> _in = new HashMap<String,Integer>();
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new FileReader(new File(filename)));
			String line = "";
			while((line = reader.readLine()) != null){
				String[] _map = line.split("\t\t");
				_in.put(_map[0], Integer.parseInt(_map[1]));
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally{
			if(reader != null){
				try {
					reader.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
		for(int i=0;i<13;i++){
			int maxDu = -1;
			String maxKey = "";
			for(String key : _in.keySet()){
				int du = _in.get(key);
				if((du >= maxDu) && !mostImportant10Pages.containsKey(key)){
					maxKey = key;
					maxDu = du;
				}
			}
			mostImportant10Pages.put(maxKey, maxDu);
		}
		
		System.setOut(new PrintStream(new File("analysis\\mostImportant10Pages.txt")));
		for(String key : mostImportant10Pages.keySet()){
			int value = mostImportant10Pages.get(key);
			System.out.println(key + "\t\t" + value);
		}
		
	}
	
	/**
	 * 入度排在前10的网页
	 */
	public static void getMostImportant10Pages(){
		for(int i=0;i<10;i++){
			int maxDu = -1;
			String maxKey = "";
			for(String key : in.keySet()){
				int du = in.get(key);
				if((du >= maxDu) && !mostImportant10Pages.containsKey(key)){
					maxKey = key;
					maxDu = du;
				}
			}
			mostImportant10Pages.put(maxKey, maxDu);
		}
	}
	
	public static void map_in_out_mostImportant10Pages_toDisk() throws Exception{
		System.setOut(new PrintStream(new File("analysis\\wangyi_map.txt")));
		for(String key : map.keySet()){
			String value = map.get(key);
			System.out.println(key + "\t\t" + value);
		}
		
		System.setOut(new PrintStream(new File("analysis\\wangyi_out.txt")));
		for(String key : out.keySet()){
			int value = out.get(key);
			System.out.println(key + "\t\t" + value);
		}
		
		System.setOut(new PrintStream(new File("analysis\\wangyi_in.txt")));
		for(String key : in.keySet()){
			int value = in.get(key);
			System.out.println(key + "\t\t" + value);
		}
		
		System.setOut(new PrintStream(new File("analysis\\wangyi_mostImportant10Pages.txt")));
		for(String key : mostImportant10Pages.keySet()){
			int value = mostImportant10Pages.get(key);
			System.out.println(key + "\t\t" + value);
		}
	}
	
	public static void main(String[] args){
		try {
			process();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}



上面四个文件放在了Heritrix工程下,运行Analysis即可。经过大概半个小时的处理,能够生成一个analysis的文件夹,然后在里面有in.txt out.txt map.txt 和 mostImportant10Pages.txt四个文件。
4。抓取的crawl report截图如下:


  • 大小: 15.8 KB
  • 大小: 97.3 KB
分享到:
评论

相关推荐

    南京大学软件学院软件体系结构作业

    5. **文档编写**:除了实际的代码实现,良好的文档也是体系结构作业的重要组成部分。每个部分完成后,学生需要编写清晰、详尽的文档,包括设计决策、实现细节和测试报告,这有助于提升团队协作和后续的维护工作。 6...

    软件体系结构大作业

    【软件体系结构大作业】主要探讨的是面向电子政务的数据交换平台的体系结构设计。这个大作业聚焦于在互联网迅速发展的背景下,如何利用中间件技术构建一个高效、可扩展且标准化的电子政务系统。 1. **项目背景和...

    软件体系结构课后作业及答案1

    在软件开发领域,软件体系结构(Software Architecture)扮演着至关重要的角色。...B/S体系结构(浏览器/服务器)则更倾向于分布式,用户界面与服务器分离,便于维护和更新,但可能对网络带宽有较高要求。

    北京理工大学《计算机体系结构》习题解答.pdf

    除了传统计算机体系结构外,一些新型计算机体系结构如量子计算、光子计算、神经网络计算机等也在不断的发展中,这些都是体系结构领域的研究前沿。 虽然无法根据文件的具体内容生成知识点,但以上内容能够为学习...

    软件体系结构作业.doc

    软件体系结构作业 本文总结了软件体系结构的基本概念、构件获取和管理、软件体系结构的定义和作用、软件体系结构风格等知识点。 一、基于构件的软件开发方法 软件体系结构作业中,基于构件的软件开发方法能够有效...

    中科大-高级计算机体系结构课程ppt-并行计算机

    【标题与描述解析】 "中科大-高级计算机体系结构课程ppt-并行计算机" 这个...通过这些PPT和作业答案,学习者可以深入理解并行计算机的原理、架构、编程模型以及性能优化策略,对高级计算机体系结构有更全面的认识。

    软件标准体系结构作业.docx

    在本作业中,我们关注两种主要的体系结构风格:层次系统体系结构和基于消息的层次体系结构。 1. 层次系统体系结构强调的是组件的层级关系,每一层都向上一层提供服务,并作为下一层的用户。这种结构允许通过添加新...

    高级计算机体系结构作业汇总(非标准答案).doc

    数据流,SIMD)SIMD系统中,所有处理器接收到同一指令...以上内容涵盖了高级计算机体系结构中的核心概念,包括系统设计、并行计算、存储架构、指令集和虚拟化技术等多个方面,这些都是理解和设计高性能计算系统的基础。

    山东大学计算机体系结构复习资料

    9. **计算机网络与互联网**:虽然不是体系结构的直接部分,但网络协议栈的理解对于现代计算机系统至关重要,包括TCP/IP协议族的工作原理。 10. **编译器与程序优化**:讲解编译器如何将高级语言转化为机器语言,并...

    体系结构大作业(软工07级)

    【体系结构大作业(软工07级)】是一个关于软件工程中体系结构设计的专题研究,特别是聚焦于“面向电子政务的数据交换平台”的体系结构设计。电子政务是指政府利用现代信息技术,通过互联网提供信息和服务,提升政府...

    中科大软院软件体系结构作业题目及答课件、书籍等相关资料

    中科大软院在《软件体系结构》这一课程中,提供了丰富的学习资源,包括授课课件、书籍推荐、作业题目以及答案解析等,旨在帮助学生深刻理解并掌握软件体系结构的精髓。 课件和讲义是学习软件体系结构的起点。它们...

    软件体系结构大作业.doc

    1. C2风格:C2体系结构风格能够概括为:经过连接件绑定在一起的按照一组规则运作的并行构件网络。 2. 数据抽象和面向对象风格:当前软件界已普遍转向使用面向对象系统,抽象数据类型概念对软件系统有着重要作用。...

    体系结构作业11

    【体系结构作业11】主要探讨了两个质量属性——可移植性和可扩展性,并通过具体场景分析了这两个属性。此外,还讨论了复杂度和成本是否可以被视为质量属性。 1. 可移植性: 可移植性是一般场景中的重要概念,涉及...

    福师春计算机体系结构在线作业一样本.doc

    福师春计算机体系结构在线作业一样本涵盖了计算机体系结构的基础知识和前沿技术,涵盖了计算机系统的结构、指令系统、流水线、存储器系统、输入/输出系统、中断系统、计算机网络等方面的知识。 一、计算机系统结构 ...

    计算机体系结构第五版作业参考答案

    这份"计算机体系结构第五版作业参考答案"提供了对这门课程各章节作业的详细解答,帮助学生深入理解并巩固所学知识。 一、处理器体系结构 处理器是计算机的核心部件,其设计包括指令集架构(ISA)、微架构以及运算器...

    体系结构学习代码!特别详细丰富

     【例6.17】事件体系结构-观察者模式-大草原1  【例6.18】事件体系结构-观察者模式-大草原2  【例6.19】事件体系结构-观察者模式-温度显示  【例6.21】层次架构-软件测试  【例6.22】层次架构-银行- ...

    软件设计模式作业+答案

    基于网络的软件体系结构: 客户端-服务器软件体系结构(Client-Server Architecture):一种分布式的软件体系结构,客户端和服务器之间的交互和通信。 P2P 软件体系结构(Peer-to-Peer Architecture):一种非集中...

    软件体系结构大作业要求资料.docx

    本次大作业的核心目标就是帮助学生在实践中学习软件体系结构的相关知识。首先,学生需要进行需求分析,这一步骤是软件开发的起点。需求分析的主要目的是要理解用户的需求并将其转化为系统需求。为了实现这一目标,...

Global site tag (gtag.js) - Google Analytics