详细代码请见

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完整代码的更多相关文章

  1. 【搜索引擎Jediael开发笔记1】搜索引擎初步介绍及网络爬虫

    详细可参考 (1)书箱:<这就是搜索引擎><自己动手写网络爬虫><解密搜索引擎打桩实践> (2)[搜索引擎基础知识1]搜索引擎的技术架构 (3)[搜索引擎基础知识2 ...

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

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

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

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

  4. 【搜索引擎Jediael开发笔记3】使用HtmlParser提取网页中的链接

    关于HtmpParser的基本内容请见 HtmlParser基础教程 本文示例用于提取HTML文件中的链接 package org.ljh.search.html; import java.util. ...

  5. 【搜索引擎Jediael开发笔记2】使用HttpClient下载网页至本地文件

    本文使用HttpClient根据url进行网页下载.其中 (1)HttpClient的相关知识请参见HttpClient基础教程 (2) package org.ljh.search.download ...

  6. 【搜索引擎Jediael开发4】V0.01完整代码

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

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

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

  8. Javascript开发笔记:不完整的继承

    Javascript的继承和标准的oop继承有很大的区别,Javascript的继承是采用原型链的技术,每个类都会将“成员变量”和“成员函数”放到 prototype 上,Js++都过supercla ...

  9. Lucene/Solr搜索引擎开发笔记 - 第1章 Solr安装与部署(Jetty篇)

    一.为何开博客写<Lucene/Solr搜索引擎开发笔记> 本人毕业于2011年,2011-2014的三年时间里,在深圳前50强企业工作,从事工业控制领域的机器视觉方向,主要使用语言为C/ ...

随机推荐

  1. Qt调用外部程序QProcess通信

    mainwindow.cpp文件: -------------------------------- #include "mainwindow.h" #include " ...

  2. [uva11916] Emoogle Grid (离散对数)

    转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud  Emoogle Grid  You have to color an MxN ( ...

  3. android listview Caused by: java.lang.ArrayIndexOutOfBoundsException: length=3; index=3

    android listview 适配器在多种类型viewType报错: Caused by: java.lang.ArrayIndexOutOfBoundsException: length=3; ...

  4. 关于link, visited, hover, active

    LoVe/HAte 如果只是希望点击的时候显示背景色,那么只需要设置 :active,无需设置:hover #navbar:active, #backbtn:active { background-c ...

  5. BZOJ NOI十连测 第二测 T2

    思路:20%可以搜索.. #include<algorithm> #include<cstdio> #include<cmath> #include<cstr ...

  6. linux下类似Bus Hound的工具

    0推荐在linux大家有时候需要调试usb接口的串口消息,但是没有类似于windows下的bus hound工具,感觉比较痛苦,其实linux内核提供了usbmon这个工具,可以收集串口信息. 1.准 ...

  7. C# 集合性能比较(代码测试)

    using System; using System.Collections; using System.Collections.Generic; using System.Data; using S ...

  8. aliyun 安装图形

    yum安装图形界面: 1) yum groupinstall "X Window System" yum install xclock yum groupinstall -y &q ...

  9. 转:ReportViewer控件使用方法

    a. ReportViewer关联Report1.rdlc的简单呈现b. 对带有报表参数的Report1.rdlc的呈现c. 利用程式生成的DataSet 填充报表d. 调用存储过程 生成DataSe ...

  10. Mod_python: The Long Story

    mod_python: the long story - Grisha Trubetskoy Mod_python: The Long Story Oct 25th, 2013 | Comments ...