详细代码请见

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 {

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

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();
}
} }

 

 

 

 

版权声明:本文为博主原创文章,未经博主允许不得转载。

【搜索引擎Jediael开发笔记】v0.1完整代码 2014-05-26 15:17 463人阅读 评论(0) 收藏的更多相关文章

  1. 【搜索引擎Jediael开发笔记】V0.1完整代码 2014-05-26 15:16 443人阅读 评论(0) 收藏

    详细代码请见 E:\Project\[重要]归档代码\SearchEngine归档代码 或 https://code.csdn.net/jediael_lu/jediael/tree/10991c83 ...

  2. shell入门之变量测试 分类: 学习笔记 linux ubuntu 2015-07-10 15:49 31人阅读 评论(0) 收藏

    格式:test 测试条件 字符串测试: 注意空格: test str1 == str2 测试字符串是否相等 test str1 != str2 测试字符串是否不相等 test str1 测试字符串是否 ...

  3. ubuntu常用文件搜索命令 分类: linux 学习笔记 ubuntu 2015-07-05 15:40 84人阅读 评论(0) 收藏

    1.find find [搜索路径] [搜索关键字] 比如查找/test中文件名为t5.tmp的文件: 查找根目录下大于100M的文件 注意,这里的204800单位是块,1块=512字节 在根目录下查 ...

  4. iOS开发 调用系统相机和相册 分类: ios技术 2015-03-30 15:52 65人阅读 评论(0) 收藏

     调用系统相机和相册 (iPad,iPhone) 打开相机:(iPad,iPhone) //先设定sourceType为相机,然后判断相机是否可用(ipod)没相机,不可用将sourceType设定为 ...

  5. 架构师速成6.7-设计开发思路-uml 分类: 架构师速成 2015-07-29 18:25 157人阅读 评论(0) 收藏

    uml是什么东西?统一建模语言,一门语言,是用来进行软件设计的一门语言. 其实一门语言的诞生并不伟大,让大多数人都使用才足够伟大.uml就是一门伟大的语言,因为目前软件设计的唯一语言就是它. UML其 ...

  6. 【搜索引擎Jediael开发4】V0.01完整代码 分类: H_HISTORY 2014-05-21 21:35 470人阅读 评论(0) 收藏

    截止目前,已完成如下功能: 1.指定某个地址,使用HttpClient下载该网页至本地文件 2.使用HtmlParser解释第1步下载的网页,抽取其中包含的链接信息 3.下载第2步的所有链接指向的网页 ...

  7. vs2008 多人同时开发项目时的代码注释规范格式 分类: C#小技巧 2014-04-23 14:12 297人阅读 评论(0) 收藏

    多人同时开发一个项目,区分项目的那个窗体是谁开发的,例:下面的格式 /************************************************       模块:服务器设置   ...

  8. android开发之调试技巧 分类: android 学习笔记 2015-07-18 21:30 140人阅读 评论(0) 收藏

    我们都知道,android的调试打了断点之后运行时要使用debug as->android application 但是这样的运行效率非常低,那么我们有没有快速的方法呢? 当然有. 我们打完断点 ...

  9. 善用VS中的Code Snippet来提高开发效率 分类: C# 2015-01-22 11:06 69人阅读 评论(0) 收藏

    前言  在谈谈VS中的模板中,我介绍了如何创建项目/项模板,这种方式可以在创建项目时省却不少重复性的工作,从而提高开发效率.在创建好了项目和文件后,就得开始具体的编码了,这时又有了新的重复性工作,就是 ...

随机推荐

  1. 利用hibernateTemplate进行最简单的分页

    安全的方法例如以下.别用Session s=getSession()........ /**  * 使用hql 语句进行操作  * @param hql HSQL 查询语句  * @param off ...

  2. shell-手机屏幕录制

    今天在做android联系的时候,想要把自己写的demo效果记录下来.在网上发现了录制手机屏幕的方法,如下 adb shell screenrecord /sdcard/demo.mp4 解释 adb ...

  3. PHP和JSON

    PHP和JSON 一.总结 1.php中json的使用方法:php中json的使用超级简单啦,主要是两个函数json_encode(编码)和json_decode(解码),像md5加密 2.json的 ...

  4. Mysql数据库存储引擎--转

    原文地址:http://pangge.blog.51cto.com/6013757/1303893 简单介绍 存储引擎就是指表的类型.数据库的存储引擎决定了表在计算机中的存储方式.存储引擎的概念是My ...

  5. using可以用于释放操作,相当于Dispose()

    using可以用于释放操作,相当于Dispose()

  6. 关于Django的登录系统

    首先需要明确的是登录的本质:登录就是服务器确认当前用户的身份,并将数据库中的记录提取匹配 默认的登录系统是用户名密码方式,这种方式很平常,也没什么特别的.这里主要说的是第三方验证登录 通常第三方验证登 ...

  7. 洛谷 P1480 A/B Problem

    P1480 A/B Problem 题目描述 输入两个整数a,b,输出它们的商(a<=10^5000,b<=10^9) 输入输出格式 输入格式: 两行,第一行是被除数,第二行是除数. 输出 ...

  8. iOS界面生命周期过程具体解释

    开发过Android的人都知道,每个Android界面就是一个Activity,而每个Activity都会有自己的生命周期, 有一系列方法会控制Activity的生命周期.如:onCreate(),o ...

  9. [TS] Implement a singly linked list in TypeScript

    In a singly linked list each node in the list stores the contents of the node and a reference (or po ...

  10. Linux下改动Oracle数据库字符集命令

    常见情形:从server备份Oracle数据库后再到本地机器上还原Oracle数据库的时候常常会碰见数据库字符编码不一致的情况,能够用下面命令来改动本地的Oracle数据库字符编码,然后顺利还原Ora ...