Java应用开源框架实现简易web搜索引擎
引言
应用Java的开源库,编写一个搜索引擎,这个引擎能爬取一个网站的内容。并根据网页内容进行深度爬取,获取所有相关的网页地址和内容,用户可以通过关键词,搜索所有相关的网址。
具体功能
(1)用户可以指定爬取一个url对应的网页的内容。
(2)对网页内容进行解析,并获取其中所有的url链接地址。
(3)用户可以设定爬取深度,代表着从初始url对应的页面开始,可以爬取其中所有的url对应的网页内的url,以此类推。深度越大,能爬取到的网站越多。
(4)对爬取到的url内容进行保存、建立索引。建立索引的内容是url地址本身,和url对应的网页标题。
(5)用户可以通过关键词对网址进行搜索,找出有该关键词的url地址。
(6)建立索引和搜索索引的过程能智能识别中文关键词,能对关键词进行分词操作。
(7)用户可以指定保存索引的地址、初始url、爬取深度、进行搜索的关键词和最大匹配项。
开源框架
- Lucene
- Jsoup
源码
爬虫部分:Spider.java
packagewebCrawler.Spider;
importjava.io.IOException;
importjava.util.ArrayList;
importjava.util.HashSet;
importjava.util.Scanner;
importorg.jsoup.Jsoup;
importorg.jsoup.nodes.Document;
importorg.jsoup.nodes.Element;
importorg.jsoup.select.Elements;
importwebCrawler.Index.BuildIndex;
/**
*@authorlannooo
*/
publicclassSpider{
ArrayListURLs;
privateStringstartURL;
privateintdigLevel;
/**
*@paramstartURL爬虫的起始URL
*@paramdigLevel爬取深度
*/
publicSpider(StringstartURL,intdigLevel){
this.startURL=startURL;
this.digLevel=digLevel;
this.URLs=newArrayList<>();
}
/**
*@paramlevel当前爬取的深度剩余
*@paramarrayList需要进行下一轮爬去的URL集
*@return从一格url集爬取到的新的URL集
*@throwsIOException
*/
publicArrayListgetLevelURLs(intlevel,ArrayListarrayList)
throwsIOException{
ArrayListtotal=null;
if(level>0){
total=newArrayList<>();
for(Stringurl:arrayList){
/*对于每个arrayList中的URL,首先解析其网页内容,并获得里面所有URL项*/
for(Stringeach:getBareLinks(url)){
total.add(each);
}
}
/*用HashSet这个容器将total里面重复项删除*/
HashSethashSet=newHashSet<>(total);
total=newArrayList<>(hashSet);
}
returntotal;
}
/**
*从startURL开始,爬取所有相关URLs
*@throwsIOException
*/
publicvoidgetAll()throwsIOException{
ArrayListnewURLs;
ArrayListcurrentURLs=newArrayList<>();
/*把startURL加入currentURLs这个列表中,从这个url开始爬*/
currentURLs.add(startURL);
for(inti=digLevel;i>0;i--){
/*
*对于每一层,都要获取一次由这个url引申出去的url集
*然后把当前集的已经爬去过的url加入到总的URL集中
*最后newURLs作为新的需要进行深度爬取的集进入下一轮循环
*/
System.out.println("Digintolevel:"+(digLevel-i+1));
newURLs=getLevelURLs(i,currentURLs);
for(Stringeach:currentURLs){
URLs.add(each);
}
currentURLs=newURLs;
}
for(Stringeach:currentURLs){
URLs.add(each);
}
HashSethashSet=newHashSet<>(URLs);
URLs=newArrayList<>(hashSet);
}
/**
*@parampath保存索引的路径
*@throwsIOException
*/
publicvoidstoreURLsAndInfo(Stringpath)throwsIOException{
BuildIndexbuild=newBuildIndex(path);
/*把URLs中的所有url进行实际网页标题的爬取*/
for(Stringeach:URLs){
Stringtext=getLinkText(each);
if(text!=null){
build.addField("url",each);
build.addField("text",text);
/*将这一个entry加入索引中*/
build.pushIndex();
}
}
build.close();
}
/**
*@paramurl需要获取网页标题的url
*@return标题内容
*@throwsIOException
*/
publicStringgetLinkText(Stringurl)throwsIOException{
Documentdocument=null;
try{
/*用Jsoup进行连接,设置超时时间为3秒*/
document=Jsoup.connect(url).timeout(3000).get();
}catch(Exceptione){
System.out.println("[TIMEOUT]Gettitleofurl:"+url);
returnnull;
}
Stringtitle=document.title();
returntitle;
}
/**
*@paramurl进行内容解析的url
*@return返回该url的网页内容内的所有urls列表
*@throwsIOException
*/
publicArrayListgetBareLinks(Stringurl)throwsIOException{
ArrayListlinksList=newArrayList<>();
Documentdocument;
try{
document=Jsoup.connect(url).timeout(2000).get();
}catch(Exceptione){
returnlinksList;
}
/*获取标签理的所有带href属性的标签*/
Elementslinks=document.select("body").select("a[href]");
for(Elementlink:links){
/*从每一个解析得到的标签中提取url,并去除锚点*/
Stringhref=link.attr("abs:href").replaceAll("#","");
/*只添加含有zju.edu.cn字符的url,去除末尾的'/'*/
if(href.contains("zju.edu.cn")){
if(href.endsWith("/")){
href=href.substring(0,href.length()-1);
}
linksList.add(href);
}
}
HashSethashSet=newHashSet<>(linksList);
ArrayListarrayList=newArrayList<>(hashSet);
returnarrayList;
}
publicstaticvoidmain(String[]args){
Scannerin=newScanner(System.in);
System.out.println("Enterurl:");
Stringurl=in.nextLine().trim();
while(!url.startsWith("http://")){
System.out.println("http://isneeded!");
System.out.println("Enterurl:");
url=in.nextLine().trim();
}
System.out.println("Enterdepthtodigmoreurls[<=3recommended]:");
intdepth=in.nextInt();
Spiderspider=newSpider(url,depth);
System.out.println("Enterpathyouwanttosave[default=d:/index-spider]:");
Stringpath=in.nextLine().trim();
if(path.length()==0){
path="d:/index-spider";
}
try{
System.out.println("Startfetching...");
spider.getAll();
System.out.println("Urlsgotsuccess!");
spider.storeURLsAndInfo(path);
System.out.println("Storedsuccess!");
}catch(IOExceptione){
e.printStackTrace();
}
}
}
建立索引:BuildIndex.java
packagewebCrawler.Index;
importjava.io.*;
importorg.apache.lucene.analysis.Analyzer;
importorg.apache.lucene.document.Document;
importorg.apache.lucene.document.Field;
importorg.apache.lucene.document.TextField;
importorg.apache.lucene.index.IndexWriter;
importorg.apache.lucene.index.IndexWriterConfig;
importorg.apache.lucene.store.Directory;
importorg.apache.lucene.store.FSDirectory;
importorg.apache.lucene.util.Version;
importorg.wltea.analyzer.lucene.IKAnalyzer;
/**
*@authorlannooo
*
*/
publicclassBuildIndex{
privateFilefile;
privateDirectorydirectory;
privateIndexWriterindexWriter;
privateIndexWriterConfigconfig;
privateAnalyzeranalyzer;
privateDocumentdocument;
/**
*@parampath建立索引的路径
*/
publicBuildIndex(Stringpath){
try{
file=newFile(path);
directory=FSDirectory.open(file);
document=newDocument();
analyzer=newIKAnalyzer();/*中文分词工具类*/
config=newIndexWriterConfig(Version.LUCENE_4_10_0,analyzer);
indexWriter=newIndexWriter(directory,config);
}catch(Exceptione){
e.printStackTrace();
}
}
/**
*@paramfieldName加入到document中的新的一项的名称
*@paramfieldText新的一项的内容
*/
publicvoidaddField(StringfieldName,StringfieldText){
try{
Fieldfield=newTextField(fieldName,fieldText,Field.Store.YES);
document.add(field);
}catch(Exceptione){
e.printStackTrace();
}
}
/**
*将document加入到索引中
*/
publicvoidpushIndex(){
try{
indexWriter.addDocument(document);
document=newDocument();
}catch(Exceptione){
e.printStackTrace();
}
}
/**
*加入完整的一个document并保存到索引中
*@paramurl加入的url地址
*@paramtexturl对应的文本
*/
publicvoidaddOneIndex(Stringurl,Stringtext){
this.addField("url",url);
this.addField("text",text);
this.pushIndex();
}
/**
*关闭索引写入
*/
publicvoidclose(){
try{
indexWriter.close();
}catch(Exceptione){
e.printStackTrace();
}
}
}
搜索索引
packagewebCrawler.Index;
importjava.io.File;
importjava.util.Scanner;
importorg.apache.lucene.analysis.Analyzer;
importorg.apache.lucene.document.Document;
importorg.apache.lucene.index.DirectoryReader;
importorg.apache.lucene.queryparser.classic.QueryParser;
importorg.apache.lucene.search.IndexSearcher;
importorg.apache.lucene.search.Query;
importorg.apache.lucene.search.ScoreDoc;
importorg.apache.lucene.search.TopDocs;
importorg.apache.lucene.store.FSDirectory;
importorg.wltea.analyzer.lucene.IKAnalyzer;
/**
*@authorlannooo
*
*/
publicclassSearchIndex{
privateIndexSearcherindexSearcher;
privateAnalyzeranalyzer;
privateQueryParserparser;
privateQueryquery;
privateTopDocshits;
privateDirectoryReaderreader;
/**
*@parampath进行索引搜索的路径
*/
publicSearchIndex(Stringpath){
try{
reader=DirectoryReader.open(FSDirectory.open(newFile(path)));
indexSearcher=newIndexSearcher(reader);
analyzer=newIKAnalyzer();
}catch(Exceptione){
e.printStackTrace();
}
}
/**
*@paramfieldName搜索的域名称
*@paramtext搜索的内容
*@parammatchNumber最大匹配项数
*@return搜索到的最大匹配数
*/
publicintsearch(StringfieldName,Stringtext,intmatchNumber){
try{
parser=newQueryParser(fieldName,analyzer);
query=parser.parse(text);
hits=indexSearcher.search(query,matchNumber);
returnhits.totalHits;
}catch(Exceptione){
e.printStackTrace();
}
return-1;
}
/**
*打印所有的匹配项
*/
publicvoidprintHits(){
try{
System.out.println("Totalhitsnumber:"+hits.totalHits);
for(ScoreDocdoc:hits.scoreDocs){
Documentdocument=indexSearcher.doc(doc.doc);
System.out.println(document.get("url"));
System.out.println(document.get("text"));
}
reader.close();
}catch(Exceptione){
e.printStackTrace();
}
}
publicstaticvoidmain(String[]args){
/*输入关键词*/
Scannerin=newScanner(System.in);
System.out.println("Enterpathoftheindex:");
Stringpath=in.nextLine().trim();
while(path.length()==0){
System.out.println("Enterpathoftheindex:");
path=in.nextLine().trim();
}
System.out.println("Entermaxhitnumber:");
intmax=in.nextInt();
while(max<0){
System.out.println("Entermaxhitnumber:");
max=in.nextInt();
}
in.nextLine();
System.out.print("Search>>>");
Stringtext=in.nextLine().trim();
/*循环读入用户的关键词,如果是q则退出,长度为0也退出*/
while(!text.equals("q")){
if(text.length()>0){
SearchIndexsearch=newSearchIndex(path);
inthits=search.search("text",text,max);
if(hits!=-1){
search.printHits();
}
}
System.out.print("Search>>>");
text=in.nextLine().trim();
}
}
}
UI界面(这里为了方便只是命令行的形式,可以根据需求写一个GUI界面)
packagewebCrawler.UI;
importjava.util.Scanner;
importwebCrawler.Index.SearchIndex;
/**
*@authorlannooo
*
*/
publicclassUI{
publicstaticvoidmain(String[]args){
/*输入关键词*/
Scannerin=newScanner(System.in);
System.out.print("Search>>>");
Stringtext=in.nextLine().trim();
/*对于用户的关键词,如果是q则退出,长度为0也退出*/
while(!text.equals("q")&&text.length()>0){
SearchIndexsearch=newSearchIndex("d:/index-spider2");
inthits=search.search("text",text,20);
if(hits!=-1){
search.printHits();
}
System.out.print("Search>>>");
text=in.nextLine().trim();
}
}
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。