Java应用开源框架实现简易web搜索引擎
程序员文章站
2023-12-13 09:49:10
引言
应用 java 的开源库,编写一个搜索引擎,这个引擎能爬取一个网站的内容。并根据网页内容进行深度爬取,获取所有相关的网页地址和内容,用户可以通过关键词,搜索所有相关...
引言
应用 java 的开源库,编写一个搜索引擎,这个引擎能爬取一个网站的内容。并根据网页内容进行深度爬取,获取所有相关的网页地址和内容,用户可以通过关键词,搜索所有相关的网址。
具体功能
(1) 用户可以指定爬取一个url对应的网页的内容。
(2) 对网页内容进行解析,并获取其中所有的url链接地址。
(3) 用户可以设定爬取深度,代表着从初始url对应的页面开始,可以爬取其中所有的url对应的网页内的url,以此类推。深度越大,能爬取到的网站越多。
(4) 对爬取到的url内容进行保存、建立索引。建立索引的内容是url地址本身,和url对应的网页标题。
(5) 用户可以通过关键词对网址进行搜索,找出有该关键词的url地址。
(6) 建立索引和搜索索引的过程能智能识别中文关键词,能对关键词进行分词操作。
(7) 用户可以指定保存索引的地址、初始url、爬取深度、进行搜索的关键词和最大匹配项。
开源框架
- lucene
- jsoup
源码
爬虫部分:spider.java
package webcrawler.spider; import java.io.ioexception; import java.util.arraylist; import java.util.hashset; import java.util.scanner; import org.jsoup.jsoup; import org.jsoup.nodes.document; import org.jsoup.nodes.element; import org.jsoup.select.elements; import webcrawler.index.buildindex; /** * @author lannooo */ public class spider { arraylist<string> urls; private string starturl; private int diglevel; /** * @param starturl 爬虫的起始url * @param diglevel 爬取深度 */ public spider(string starturl, int diglevel){ this.starturl = starturl; this.diglevel = diglevel; this.urls = new arraylist<>(); } /** * @param level 当前爬取的深度剩余 * @param arraylist 需要进行下一轮爬去的url集 * @return 从一格url集爬取到的新的url集 * @throws ioexception */ public arraylist<string> getlevelurls(int level, arraylist<string> arraylist) throws ioexception{ arraylist<string> total = null; if(level>0){ total = new arraylist<>(); for(string url: arraylist){ /*对于每个arraylist中的url,首先解析其网页内容,并获得里面所有url项*/ for(string each: getbarelinks(url)){ total.add(each); } } /*用hashset这个容器将total里面重复项删除*/ hashset<string> hashset = new hashset<>(total); total = new arraylist<>(hashset); } return total; } /** * 从starturl开始,爬取所有相关urls * @throws ioexception */ public void getall() throws ioexception{ arraylist<string> newurls; arraylist<string> currenturls = new arraylist<>(); /*把starturl加入currenturls这个列表中,从这个url开始爬*/ currenturls.add(starturl); for(int i=diglevel; i>0; i--){ /* * 对于每一层,都要获取一次由这个url引申出去的url集 * 然后把当前集的已经爬去过的url加入到总的url集中 * 最后newurls作为新的需要进行深度爬取的集进入下一轮循环 */ system.out.println("dig into level: " + (diglevel-i+1)); newurls = getlevelurls(i, currenturls); for(string each: currenturls){ urls.add(each); } currenturls = newurls; } for(string each:currenturls){ urls.add(each); } hashset<string> hashset = new hashset<>(urls); urls = new arraylist<>(hashset); } /** * @param path 保存索引的路径 * @throws ioexception */ public void storeurlsandinfo(string path) throws ioexception{ buildindex build = new buildindex(path); /* 把urls中的所有url进行实际网页标题的爬取*/ for(string each:urls){ string text = getlinktext(each); if(text!=null){ build.addfield("url", each); build.addfield("text", text); /*将这一个entry加入索引中*/ build.pushindex(); } } build.close(); } /** * @param url 需要获取网页标题的url * @return 标题内容 * @throws ioexception */ public string getlinktext(string url) throws ioexception{ document document = null; try { /*用jsoup进行连接,设置超时时间为3秒*/ document = jsoup.connect(url).timeout(3000).get(); } catch (exception e) { system.out.println("[timeout]get title of url:"+url); return null; } string title = document.title(); return title; } /** * @param url 进行内容解析的url * @return 返回该url的网页内容内的所有urls列表 * @throws ioexception */ public arraylist<string> getbarelinks(string url) throws ioexception{ arraylist<string> linkslist = new arraylist<>(); document document; try { document = jsoup.connect(url).timeout(2000).get(); } catch (exception e) { return linkslist; } /*获取<body>标签理的所有带href属性的<a>标签*/ elements links = document.select("body").select("a[href]"); for(element link: links){ /*从每一个解析得到的<a>标签中提取url,并去除锚点*/ string href = 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); } } hashset<string> hashset = new hashset<>(linkslist); arraylist<string> arraylist = new arraylist<>(hashset); return arraylist; } public static void main(string[] args) { scanner in = new scanner(system.in); system.out.println("enter url:"); string url = in.nextline().trim(); while(!url.startswith("http://")){ system.out.println("http:// is needed!"); system.out.println("enter url:"); url = in.nextline().trim(); } system.out.println("enter depth to dig more urls[<=3 recommended]:"); int depth = in.nextint(); spider spider = new spider(url, depth); system.out.println("enter path you want to save[default=d:/index-spider]:"); string path = in.nextline().trim(); if(path.length()==0){ path = "d:/index-spider"; } try { system.out.println("start fetching..."); spider.getall(); system.out.println("urls got success!"); spider.storeurlsandinfo(path); system.out.println("stored success!"); } catch (ioexception e) { e.printstacktrace(); } } }
建立索引:buildindex.java
package webcrawler.index; import java.io.*; import org.apache.lucene.analysis.analyzer; import org.apache.lucene.document.document; import org.apache.lucene.document.field; import org.apache.lucene.document.textfield; import org.apache.lucene.index.indexwriter; import org.apache.lucene.index.indexwriterconfig; import org.apache.lucene.store.directory; import org.apache.lucene.store.fsdirectory; import org.apache.lucene.util.version; import org.wltea.analyzer.lucene.ikanalyzer; /** * @author lannooo * */ public class buildindex { private file file; private directory directory; private indexwriter indexwriter; private indexwriterconfig config; private analyzer analyzer; private document document; /** * @param path 建立索引的路径 */ public buildindex(string path) { try { file = new file(path); directory = fsdirectory.open(file); document = new document(); analyzer = new ikanalyzer(); /*中文分词工具类*/ config = new indexwriterconfig(version.lucene_4_10_0, analyzer); indexwriter = new indexwriter(directory, config); } catch (exception e) { e.printstacktrace(); } } /** * @param fieldname 加入到document中的新的一项的名称 * @param fieldtext 新的一项的内容 */ public void addfield(string fieldname, string fieldtext){ try{ field field = new textfield(fieldname, fieldtext, field.store.yes); document.add(field); }catch (exception e) { e.printstacktrace(); } } /** * 将document加入到索引中 */ public void pushindex(){ try { indexwriter.adddocument(document); document = new document(); } catch (exception e) { e.printstacktrace(); } } /** * 加入完整的一个document并保存到索引中 * @param url 加入的url地址 * @param text url对应的文本 */ public void addoneindex(string url, string text){ this.addfield("url", url); this.addfield("text", text); this.pushindex(); } /** * 关闭索引写入 */ public void close(){ try { indexwriter.close(); } catch (exception e) { e.printstacktrace(); } } }
搜索索引
package webcrawler.index; import java.io.file; import java.util.scanner; import org.apache.lucene.analysis.analyzer; import org.apache.lucene.document.document; import org.apache.lucene.index.directoryreader; import org.apache.lucene.queryparser.classic.queryparser; import org.apache.lucene.search.indexsearcher; import org.apache.lucene.search.query; import org.apache.lucene.search.scoredoc; import org.apache.lucene.search.topdocs; import org.apache.lucene.store.fsdirectory; import org.wltea.analyzer.lucene.ikanalyzer; /** * @author lannooo * */ public class searchindex { private indexsearcher indexsearcher; private analyzer analyzer; private queryparser parser; private query query; private topdocs hits; private directoryreader reader; /** * @param path 进行索引搜索的路径 */ public searchindex(string path){ try { reader = directoryreader.open(fsdirectory.open(new file(path))); indexsearcher = new indexsearcher(reader); analyzer = new ikanalyzer(); } catch (exception e) { e.printstacktrace(); } } /** * @param fieldname 搜索的域名称 * @param text 搜索的内容 * @param matchnumber 最大匹配项数 * @return 搜索到的最大匹配数 */ public int search(string fieldname, string text, int matchnumber){ try { parser = new queryparser(fieldname, analyzer); query = parser.parse(text); hits = indexsearcher.search(query, matchnumber); return hits.totalhits; } catch (exception e) { e.printstacktrace(); } return -1; } /** * 打印所有的匹配项 */ public void printhits(){ try{ system.out.println("total hits number:"+hits.totalhits); for(scoredoc doc: hits.scoredocs){ document document = indexsearcher.doc(doc.doc); system.out.println(document.get("url")); system.out.println(document.get("text")); } reader.close(); }catch (exception e) { e.printstacktrace(); } } public static void main(string[] args) { /*输入关键词*/ scanner in = new scanner(system.in); system.out.println("enter path of the index:"); string path = in.nextline().trim(); while(path.length()==0){ system.out.println("enter path of the index:"); path = in.nextline().trim(); } system.out.println("enter max hit number:"); int max = in.nextint(); while(max<0){ system.out.println("enter max hit number:"); max = in.nextint(); } in.nextline(); system.out.print("search>>> "); string text = in.nextline().trim(); /*循环读入用户的关键词,如果是q则退出,长度为0也退出*/ while(!text.equals("q")){ if(text.length()>0){ searchindex search = new searchindex(path); int hits = search.search("text", text, max); if(hits!=-1){ search.printhits(); } } system.out.print("search>>> "); text = in.nextline().trim(); } } }
ui界面(这里为了方便只是命令行的形式,可以根据需求写一个gui界面)
package webcrawler.ui; import java.util.scanner; import webcrawler.index.searchindex; /** * @author lannooo * */ public class ui { public static void main(string[] args) { /*输入关键词*/ scanner in = new scanner(system.in); system.out.print("search>>> "); string text = in.nextline().trim(); /*对于用户的关键词,如果是q则退出,长度为0也退出*/ while(!text.equals("q") && text.length()>0){ searchindex search = new searchindex("d:/index-spider2"); int hits = search.search("text", text, 20); if(hits!=-1){ search.printhits(); } system.out.print("search>>> "); text = in.nextline().trim(); } } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。