zoukankan      html  css  js  c++  java
  • 【搜索引擎Jediael开发笔记】V0.1完整代码

    详细代码请见

    E:Project【重要】归档代码SearchEngine归档代码

    https://code.csdn.net/jediael_lu/jediael/tree/10991c839c51d32f825708b09451b2618a20ee94

    http://download.csdn.net/detail/jediael_lu/7402827


    本版本完成以下功能:

    (1)创建用于保存种子URL的配置文件及其数据结构

    (2)创建用于保存Todo信息(未下载URL)的数据结构

    (3)创建用于保存Visited信息(已下载的URL)的数据结构

    (4)下载网页时同步更新Tode与Visited。下载网页前,判断某个网页是否已经下载过。

    (5)从上述第3步下载的网页抽取链接并继续下载,直到Todo列表为空。

    (6)为每个种子url创建一个独立的线程。

    至此,搜索引擎已具体基本功能。


    下一阶段工作:

    (1)引入dao,使用数据库保存一些信息,如种子url等?

    (2)使用Berkey DB保存Frontier?使用布隆过滤器保存已访问的url。

    (3)继续学习后面内容,引入其它内容。如访问blog.csdn.net时,返回403。


    1、创建用于保存种子url的数据结构

    由于一般而言,种子url的数据量均小,因此先使用PriorityQueue,以图方便,今后视应用情况修改成其它数据结构。

    package org.ljh.search.frontier;
    
    import java.util.PriorityQueue;
    
    public class SeekUrlQueue {
    <span style="white-space:pre">	</span>
    <span style="white-space:pre">	</span>//保存种子url的队列。由于一般而言,种子url的数据量均小,因此先使用PriorityQueue,以图方便,今后视应用情况修改成其它数据结构。
    <span style="white-space:pre">	</span>private PriorityQueue<String> seekUrlQueue = new PriorityQueue<String>();
    
    
    <span style="white-space:pre">	</span>//Getter
    <span style="white-space:pre">	</span>public PriorityQueue<String> getSeekUrlQueue() {
    <span style="white-space:pre">		</span>return seekUrlQueue;
    <span style="white-space:pre">	</span>}
    <span style="white-space:pre">	</span>
    <span style="white-space:pre">	</span>//将url添加至种子url队列中
    <span style="white-space:pre">	</span>public boolean add(String url){
    <span style="white-space:pre">		</span>return seekUrlQueue.add(url);
    <span style="white-space:pre">	</span>}
    
    <span style="white-space:pre">	</span>//判断种子url队列是否为空
    <span style="white-space:pre">	</span>public boolean isEmpty(){
    <span style="white-space:pre">		</span>return seekUrlQueue.isEmpty();
    <span style="white-space:pre">	</span>}
    <span style="white-space:pre">	</span>
    <span style="white-space:pre">	</span>//从种子url队列中获取下一个种子url
    <span style="white-space:pre">	</span>public String getNext(){
    <span style="white-space:pre">		</span>return seekUrlQueue.poll();
    <span style="white-space:pre">	</span>}<span style="white-space:pre">	</span>
    }
    

    2、创建用于保存已访问url的数据结构

    (1)先创建一个接口,用于提供最基本功能

    package org.ljh.search.frontier;
    
    public interface VisitedUrlQueue {
    	
    	//判断某个Url是否已经存在于已访问队列中
    	public  boolean contains(String url);
    	
    	//将已下载的url放入已访问的列表
    	public boolean add(String url);
    
    }
    

    (2)创建具体的实施类

    package org.ljh.search.frontier;
    
    import java.util.HashSet;
    
    public class HashSetVisitedUrlQueue implements VisitedUrlQueue{
    	
    	//用于保存已访问的Url的数据结构。由于已访问列表会被经常查询,因此,使用HashSet。由于只要其中任何一个线程下载过,此url即算做已经下载,因此使用了static。
    	private static HashSet<String> visitedUrlQueue = new HashSet<String>();
    
    	public HashSet<String> getVisitedUrlQueue() {
    		return visitedUrlQueue;
    	}
    
    	@Override
    	public boolean contains(String url) {
    		return visitedUrlQueue.contains(url);
    	}
    
    	@Override
    	public boolean add(String url) {
    		visitedUrlQueue.add(url);
    		return true;
    	}
    }
    

    3、创建待访问的url列表的数据结构

    (1)先创建接口

    package org.ljh.search.frontier;
    
    public interface Frontier {
    	//获取下一个待访问的url
    	public String getNextUrl();
    	
    	//将从其它网页中提取出来的url放到待访问url中。
    	public boolean putUrlIntoTodoQueue(String url);
    
    }

    (2)创建具体实现类

    package org.ljh.search.frontier;
    
    import java.util.PriorityQueue;
    
    public class PriorityQueueFrontier implements Frontier {
    	
    	//保存待访问的url的列表。考虑到先入先出及可在一定程度上控制访问顺序,即带偏好的宽度优先搜索策略,使用了PriorityQueue。
    	private PriorityQueue<String> todoUrlQueue = new PriorityQueue<String>();
    
    	@Override
    	public String getNextUrl() {
    		return todoUrlQueue.poll();
    	}
    
    	@Override
    	public boolean add(String url) {
    		todoUrlQueue.add(url);
    		return true;
    	}
    	
    	@Override
    	public boolean isEmpty(){
    		return todoUrlQueue.isEmpty();
    	}
    
    }
    

    4、修改主类

    (1)下载网页前,判断某个网页是否已经下载过。

    (2)分析刚下载的网页,提取链接,继续放入frontier。

    (3)为每个种子url创建一个独立的线程。

    package org.ljh.search;
    
    import java.io.IOException;
    import java.util.Iterator;
    import java.util.Set;
    
    import org.ljh.search.downloadpage.PageDownloader;
    import org.ljh.search.frontier.HashSetVisitedUrlQueue;
    import org.ljh.search.frontier.PriorityQueueFrontier;
    import org.ljh.search.frontier.SeekUrlQueue;
    import org.ljh.search.html.HtmlParserTool;
    import org.ljh.search.html.LinkFilter;
    
    public class MyCrawler {
    
    	public static void main(String[] args) {
    
    		// 种子url
    		final SeekUrlQueue seekUrlQueue = new SeekUrlQueue();
    		seekUrlQueue.add("http://www.sohu.com");
    		seekUrlQueue.add("http://www.baidu.com");
    		seekUrlQueue.add("http://www.eoeandroid.com/");
    		
    		// 已访问过的url
    		final HashSetVisitedUrlQueue visitedUrl = new HashSetVisitedUrlQueue();
    
    		// 设定过滤器,用于指明搜索范围
    		final LinkFilter linkFilter = new LinkFilter() {
    			@Override
    			public boolean accept(String url) {
    				if ((url.contains("baidu") || url.contains("sohu")||url.contains("eoe"))
    						&& !url.contains("baike") && !url.contains("@")) {
    					return true;
    				} else {
    					return false;
    				}
    			}
    		};
    
    		while (!seekUrlQueue.isEmpty()) {
    
    			// 根据种子url对frontier进行初始化
    			final String nextSeek = seekUrlQueue.getNext();
    			System.out.println(nextSeek);
    
    			//为每一个种子url,启动一个线程
    			Thread t = new Thread(new Runnable() {
    				@Override
    				public void run() {
    					// 待访问 的url
    					PriorityQueueFrontier frontier = new PriorityQueueFrontier();
    					frontier.add(nextSeek);
    					
    					//直到frontier为空,才会结束下载
    					while (!frontier.isEmpty()) {
    						//获取下一个待访问的url,然后判断是否已经访问过,若否,则下载,并将其添加到已访问列表。
    						String nextUrl = frontier.getNextUrl();
    						if (!visitedUrl.contains(nextUrl)) {
    							try {
    								PageDownloader.downloadPageByGetMethod(nextUrl);
    							} catch (IOException e) {
    								e.printStackTrace();
    							}
    							visitedUrl.add(nextUrl);
    							
    							//从刚下载的页面中提取链接,并将其放入frointier.正常而言,应该使用刚下载到本地的文件作参数,但此处还是使用了url,会导致再一次连接网络。
    							Set<String> urlSet = HtmlParserTool.extractLinks(
    									nextUrl, linkFilter);
    							Iterator<String> iterator = urlSet.iterator();
    							while (iterator.hasNext()) {
    								frontier.add(iterator.next());
    							}
    						}
    					}
    				}
    
    			});
    
    			t.start();
    		}
    	}
    
    }
    





  • 相关阅读:
    npm install报错Error: ENOENT
    hibernate hql
    mysql授权
    撤销git reset soft head操作
    nodejs&npm等概念梳理
    Java类中中文问题
    采用MANIFEST.MF之jar报错ClassNotFoundException解法
    EChart和G2比较
    牛客OI测试赛1
    Codeforces Round #340 (Div.2)
  • 原文地址:https://www.cnblogs.com/jediael/p/4304135.html
Copyright © 2011-2022 走看看