1.子链接的提取:
做页面子链接提取的基本思路是:
1.用被提取的网页的url实例化一个Parser
2.实例化Filter,设置页面过滤条件——只获取<a>标签与<frame>标签的内容
3.用Parser提取页面中所有通过Filter的结点,得到NodeList
4.遍历NodeList,调用Node的相应方法得到其中的链接,加入子链接的集合
5.返回子链接集合
代码:
package Crawler; import java.util.HashSet; import java.util.Set; import org.htmlparser.Node; import org.htmlparser.NodeFilter; import org.htmlparser.Parser; import org.htmlparser.filters.NodeClassFilter; import org.htmlparser.filters.OrFilter; import org.htmlparser.tags.LinkTag; import org.htmlparser.util.NodeList; import org.htmlparser.util.ParserException; public class HtmlLinkParser { //获取子链接,url为网页url,filter是链接过滤器,返回该页面子链接的HashSet public static Set<String> extracLinks(String url, LinkFilter filter) { Set<String> links = new HashSet<String>(); try { Parser parser = new Parser(url); parser.setEncoding("utf-8"); // 过滤 <frame >标签的 filter,用来提取 frame 标签里的 src 属性所表示的链接 NodeFilter frameFilter = new NodeFilter() { public boolean accept(Node node) { if (node.getText().startsWith("frame src=")) { return true; } else { return false; } } }; // OrFilter 接受<a>标签或<frame>标签,注意NodeClassFilter()可用来过滤一类标签,linkTag对应<标签> OrFilter linkFilter = new OrFilter(new NodeClassFilter( LinkTag.class), frameFilter); // 得到所有经过过滤的标签,结果为NodeList NodeList list = parser.extractAllNodesThatMatch(linkFilter); for (int i = 0; i < list.size(); i++) { Node tag = list.elementAt(i); if (tag instanceof LinkTag)// <a> 标签 { LinkTag link = (LinkTag) tag; String linkUrl = link.getLink();// 调用getLink()方法得到<a>标签中的链接 if (filter.accept(linkUrl))//将符合filter过滤条件的链接加入链接表 links.add(linkUrl); } else{// <frame> 标签 // 提取 frame 里 src 属性的链接如 <frame src="test.html"/> String frame = tag.getText(); int start = frame.indexOf("src="); frame = frame.substring(start); int end = frame.indexOf(" "); if (end == -1) end = frame.indexOf(">"); String frameUrl = frame.substring(5, end - 1); if (filter.accept(frameUrl)) links.add(frameUrl); } } } catch (ParserException e) {//捕捉parser的异常 e.printStackTrace(); } return links; } }
2.解析网页内容:
基本思路:
1.读取html文件,获得页面编码,获得String格式的文件内容
2.用页面编码实例化html文件的Parser
3.对需要提取的结点设置相应的Filter
4.根据给定的Filter,用Parser解析html文件
5.提取结点中的文本内容,进行处理(本例中是关键字匹配,计算主题相关度)
import java.io.BufferedReader; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.htmlparser.Parser; import org.htmlparser.filters.NodeClassFilter; import org.htmlparser.tags.HeadingTag; import org.htmlparser.tags.LinkTag; import org.htmlparser.tags.MetaTag; import org.htmlparser.tags.ParagraphTag; import org.htmlparser.tags.TitleTag; import org.htmlparser.util.NodeList; import org.htmlparser.util.ParserException; import java.util.Set; import multi.patt.match.ac.*; public class HtmlFileParser { String filepath=new String();//html文件路径 private static String[] keyWords;//关键词列表 /*static{ keyWords=read("filePath");//从指定文件中读取关键词列表 }*/ public HtmlFileParser(String filepath){ this.filepath=filepath; } public String getTitle(){//得到页面标题 FileAndEnc fae=readHtmlFile(); int i=0; try{ //实例化一个本地html文件的Parser Parser titleParser = Parser.createParser(fae.getFile(),fae.getEnc()); NodeClassFilter titleFilter =new NodeClassFilter(TitleTag.class); NodeList titleList = titleParser.extractAllNodesThatMatch(titleFilter); //实际上一个网页应该只有一个<title>标签,但extractAllNodesThatMatch方法返回的只能是一个NodeList for (i = 0; i < titleList.size(); i++) { TitleTag title_tag = (TitleTag) titleList.elementAt(i); return title_tag.getTitle(); } }catch(ParserException e) { return null; } return null; } public String getEncoding(){//获得页面编码 FileAndEnc fae=readHtmlFile(); return fae.getEnc(); } public float getRelatGrade(){//计算网页的主题相关度 FileAndEnc fae=readHtmlFile(); String file=fae.getFile(); String enC=fae.getEnc(); String curString; int curWordWei = 1;//当前关键词权重 float curTagWei = 0;//当前标签权重 float totalGra = 0;//总相关度分 int i; AcApply obj = new AcApply();//实例化ac自动机 Pattern p = null; Matcher m = null; try{//根据不同标签依次进行相关度计算 //title tag <title> curTagWei=5; Parser titleParser = Parser.createParser(file,enC); NodeClassFilter titleFilter =new NodeClassFilter(TitleTag.class); NodeList titleList = titleParser.extractAllNodesThatMatch(titleFilter); for (i = 0; i < titleList.size(); i++) { TitleTag titleTag=(TitleTag)titleList.elementAt(i); curString=titleTag.getTitle(); Set result = obj.findWordsInArray(keyWords, curString);//ac自动机的方法返回匹配的词的表 totalGra=totalGra+result.size()*curTagWei;//计算相关度 } //meta tag of description and keyword <meta> curTagWei=4; Parser metaParser = Parser.createParser(file,enC); NodeClassFilter metaFilter =new NodeClassFilter(MetaTag.class); NodeList metaList = metaParser.extractAllNodesThatMatch(metaFilter); p = Pattern.compile("\\b(description|keywords)\\b",Pattern.CASE_INSENSITIVE); for (i = 0; i < metaList.size(); i++) { MetaTag metaTag=(MetaTag)metaList.elementAt(i); curString=metaTag.getMetaTagName(); if(curString==null){ continue; } m = p.matcher(curString); //正则匹配name是description或keyword的<meta>标签 if(m.find()){ curString=metaTag.getMetaContent();//提取其content Set result = obj.findWordsInArray(keyWords, curString); totalGra=totalGra+result.size()*curTagWei; } else{ curString=metaTag.getMetaContent(); Set result = obj.findWordsInArray(keyWords, curString); totalGra=totalGra+result.size()*2; } } //heading tag <h*> curTagWei=3; Parser headingParser = Parser.createParser(file,enC); NodeClassFilter headingFilter =new NodeClassFilter(HeadingTag.class); NodeList headingList = headingParser.extractAllNodesThatMatch(headingFilter); for (i = 0; i < headingList.size(); i++) { HeadingTag headingTag=(HeadingTag)headingList.elementAt(i); curString=headingTag.toPlainTextString();//得到<h*>标签中的纯文本 if(curString==null){ continue; } Set result = obj.findWordsInArray(keyWords, curString); totalGra=totalGra+result.size()*curTagWei; } //paragraph tag <p> curTagWei=(float)2.5; Parser paraParser = Parser.createParser(file,enC); NodeClassFilter paraFilter =new NodeClassFilter(ParagraphTag.class); NodeList paraList = paraParser.extractAllNodesThatMatch(paraFilter); for (i = 0; i < paraList.size(); i++) { ParagraphTag paraTag=(ParagraphTag)paraList.elementAt(i); curString=paraTag.toPlainTextString(); if(curString==null){ continue; } Set result = obj.findWordsInArray(keyWords, curString); totalGra=totalGra+result.size()*curTagWei; } //link tag <a> curTagWei=(float)0.25; Parser linkParser = Parser.createParser(file,enC); NodeClassFilter linkFilter =new NodeClassFilter(LinkTag.class); NodeList linkList = linkParser.extractAllNodesThatMatch(linkFilter); for (i = 0; i < linkList.size(); i++) { LinkTag linkTag=(LinkTag)linkList.elementAt(i); curString=linkTag.toPlainTextString(); if(curString==null){ continue; } Set result = obj.findWordsInArray(keyWords, curString); totalGra=totalGra+result.size()*curTagWei; } }catch(ParserException e) { return 0; } return totalGra; } private FileAndEnc readHtmlFile(){//读取html文件,返回字符串格式的文件与其编码 StringBuffer abstr = new StringBuffer(); FileAndEnc fae=new FileAndEnc(); try{ //实例化默认编码方式的BufferefReader BufferedReader enCReader= new BufferedReader(new InputStreamReader(new FileInputStream(filepath),"UTF-8")); String temp=null; while((temp=enCReader.readLine())!=null){//得到字符串格式的文件 abstr.append(temp); abstr.append("\r\n"); } String result=abstr.toString(); fae.setFile(result); String encoding=getEnc(result); fae.setEnc(encoding);//得到页面编码 //根据得到的编码方式实例化BufferedReader BufferedReader reader= new BufferedReader(new InputStreamReader(new FileInputStream(filepath),encoding)); StringBuffer abstrT = new StringBuffer(); while((temp=reader.readLine())!=null){ abstrT.append(temp); abstrT.append("\r\n"); } result=abstrT.toString(); fae.setFile(result);//得到真正的页面内容 } catch (FileNotFoundException e) { System.out.println("file not found"); fae=null; } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); fae=null; } finally { return fae; } } private String getEnc(String file){//根据正则匹配得到页面编码 String enC="utf-8"; Pattern p = Pattern.compile("(charset|Charset|CHARSET)\\s*=\\s*\"?\\s*([-\\w]*?)[^-\\w]"); Matcher m = p.matcher(file); if(m.find()){ enC=m.group(2); } return enC; } }
3.使用Filter从网页中查找获取需要的内容
常用的几个过滤器说明
TagNameFilter:
是最容易理解的一个Filter,根据Tag的名字进行过滤
HasChildFilter:
是返回有符合条件的子节点的节点,需要另外一个Filter作为过滤子节点的参数。
HasAttributeFilter:
可以匹配出包含制定名字的属性,或者制定属性为指定值的节点。HasParentFilter和HasSiblingFilter的功能与HasChildFilter类似。
StringFilter:
这个Filter用于过滤显示字符串中包含指定内容的标签节点。注意是可显示的字符串,不可显示的字符串中的内容(例如注释,链接等等)不会被显示
RegexFilter :
根据正则表达式匹配节点.与LinkRegexFilter不同的是,LinkRegexFilter只在LinkTag中寻找匹配
NodeClassFilter:
根据已定义的标签类获取节点
LinkStringFilter:
这个Filter用于判断链接中是否包含某个特定的字符串,可以用来过滤出指向某个特定网站的链接。
OrFilter:
是结合几种过滤条件的'或'过滤器
AndFilter:
是结合几种过滤条件的'与'过滤器
代码:
/** * * 过滤页面中的标签信息 * * @param url 要解析的url页面 * @param encoding 使用的字符编码 * @param tagclass * 要或取得页面标签,如要获取页面中的超链接 值为LinkTag.class,要获取页面中图片链接,值为ImageTag.class * 要传入的标签类为org.htmlparser.tags下的 */ public static void nodeFilterTagClass(String url,String encoding,Class tagclass){ try { Parser parser = new Parser(); parser.setURL(url); if(null==encoding){ parser.setEncoding(parser.getEncoding()); }else{ parser.setEncoding(encoding); } //过滤页面中的链接标签 NodeFilter filter = new NodeClassFilter(tagclass); NodeList list = parser.extractAllNodesThatMatch(filter); for(int i=0; i<list.size();i++){ Node node = (Node)list.elementAt(i); System.out.println("link is :" + node.toHtml()); } } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { String url = "http://wenku.baidu.com/search?word=htmlparser&lm=0&od=0&fr=top_home"; //获取页面中的<a href='xxx' [属性]>格式的链接 nodeFilterTagClass(url, "UTF-8", LinkTag.class); //或取页面中的<img src='xxx' [属性='属性值']>格式的链接 nodeFilterTagClass(url, "UTF-8", ImageTag.class); //或取页面<title>xxxx</title>标题 nodeFilterTagClass(url, "UTF-8", TitleTag.class); //获取页面<div [属性='属性值']> xxx</div> //nodeFilterTagClass(url, "UTF-8", Div.class); }