网页解析,即程序自动分析网页内容、获取信息,从而进一步处理信息。
网页解析是实现网络爬虫中不可缺少而且十分重要的一环,由于本人经验也很有限,我仅就我们团队开发基于关键词匹配和模板匹配的主题爬虫的经验谈谈如何实现网页解析。
首先,必须说在最前的是我们使用的工具——htmlparser
简要地说,htmlparser包提供方便、简洁的处理html文件的方法,它将html页面中的标签按树形结构解析成一个一个结点,一种类型的结点对应一个类,通过调用其方法可以轻松地访问标签中的内容。
我所使用的是htmlparser2.0,也就是最新版本。强烈推荐。
好,进入正题。
对于主题爬虫,它的功能就是将与主题相关的网页下载到本地,将网页的相关信息存入数据库。
网页解析模块要实现两大功能:1.从页面中提取出子链接,加入到爬取url队列中;2.解析网页内容,与主题进行相关度计算。
由于网页内容解析需要频繁地访问网页文件,如果通过url访问网络获取文件的时间开销比较大,所以我们的做法是将爬取队列中的网页统统下载到本地,对本地的网页文件进行页面内容解析,最后删除不匹配的网页。而子链接的提取比较简单,通过网络获取页面文件即可。对于给定url通过网络访问网页,和给定文件路径访问本地网页文件,htmlparser都是支持的!
1.子链接的提取:
做页面子链接提取的基本思路是:
1.用被提取的网页的url实例化一个Parser
2.实例化Filter,设置页面过滤条件——只获取<a>标签与<frame>标签的内容
3.用Parser提取页面中所有通过Filter的结点,得到NodeList
4.遍历NodeList,调用Node的相应方法得到其中的链接,加入子链接的集合
5.返回子链接集合
OK,上代码:
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; } }
此时可能有读者在想:呵~呵~博主忽略了相对url链接的问题了(-.-)
其实我想到了,一开始我写了一个private方法专门把任何url转换成绝对url链接。后来调试的时候我发现我的方法根本没用,因为htmlparser很人性化地自动完成了这个转换!
另外,Parser是需要设置编码的,在这段程序中我直接设置为utf-8。实际上网页的编码方式是多种多样的,在<meta>标签中有关于编码方式的信息,如果编码不正确,页面的文本内容可能是乱码。不过,在子链接提取的部分,我们仅对标签内部的内容进行处理,这些内容是根据html语法编写的,不涉及编码的问题。
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; } }
读者需要注意两点:
1.用BufferedReader读取文件是需要编码方式的,但是第一次读取我们必然不知道网页的编码。好在网页对于编码的描述在html语言框架中,我们用默认的编码方式读取文件就可以获取编码。但这个读取的文件的文本内容可能因为编码不正确而产生乱码,所以得到编码后,我们应使用得到的编码再实例化一个BufferedReader读取文件,这样得到的文件就是正确的了(除非网页本身给的编码就不对)。
获得正确的编码对于解析网页内容是非常重要的,而网络上什么样的网页都有,我推荐使用比较基础、可靠的方法获得编码,我使用的是正则匹配。
举个例子:
这是http://kb.cnblogs.com/page/143965/的对编码的描述:
<meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
这是http://www.ucsd.edu/的对编码的描述:
<meta charset="utf-8"/>
2.不熟悉html的读者可能有所不知<meta>的作用,来看看博客园首页的源码:
<meta name="keywords" content="博客园,开发者,程序员,软件开发,编程,代码,极客,Developer,Programmer,Coder,Code,Coding,Greek,IT学习"/><meta name="description" content="博客园是面向程序员的高品质IT技术学习社区,是程序员学习成长的地方。博客园致力于为程序员打造一个优秀的互联网平台,帮助程序员学好IT技术,更好地用技术改变世界。" />
这两类<meta>标签的很好的描述了网页的内容
@编辑 博客园首页这个keyword的内容里这“Greek”……极客是“Geek”,“Greek”是希腊人
3.由于网页的正文通常是一段最长的纯文本内容,所以当我们得到一个<p>,<li>,<ul>标签的纯文本后,我们可以通过判断字符串的长度来得到网页的正文。
对页面大量的信息进行处理是很费时的,页面的<title>标签和<meta>标签中往往有对网页内容最精炼的描述,开发者应该考虑性能与代价
来自:http://www.cnblogs.com/coding-hundredOfYears/archive/2012/12/15/2819217.html
相关推荐
我们可以通过重写这些方法来实现自定义的解析逻辑。 下面是一个简单的HTMLParser子类,它会打印出所有遇到的标签和它们之间的文本数据: ```python class MyHTMLParser(HTMLParser): def handle_starttag(self, ...
在IT领域,网页爬虫是数据获取的重要工具,而HTMLParser是Java中一款强大的解析库,专门用于处理HTML文档。本项目就是利用HTMLParser库来编写一个基础的网页爬虫,用于爬取新浪新闻的数据,并将抓取到的数据存储到...
文章详细描述了基于HttpClient与HTMLParser实现的网页正文提取方法,该方法能够快速有效抓取HTML页面,并提取出所需的文本内容。由于文章内容中有些部分是通过OCR扫描转换的文字,可能存在字识别错误或漏识别的情况...
基于HTMLParser的Web信息抽取系统的设计与实现,是一项旨在从网页中自动提取特定信息的技术方案。随着互联网信息的爆炸性增长,如何从海量数据中快速定位到有价值的信息成为了一个亟待解决的问题。传统的HTML页面...
如何在Java程序中利用正则表达式实现对字符串的解析.另外,HTMLParser是一款很强大的对HTML网页进行解析的工具,其中大量地用到正则表达式.
4. **自动化测试**:在Web应用自动化测试中,可以使用HTMLParser验证网页的预期结构和内容。 5. **内容管理系统**:在构建内容管理系统时,HTMLParser可以帮助处理用户输入的HTML,确保安全性和一致性。 **...
在使用HttpClient和HtmlParser实现网络爬虫的过程中,首先需要设置开发环境。这里推荐使用Eclipse Europa作为集成开发环境(IDE),并确保安装了JDK 1.6。在Eclipse中创建一个新的JAVA工程,并将HttpClient和...
4. 使用示例:在"HTMLParser使用详解-Node内容.doc"中,可能详细介绍了如何创建和配置解析器对象,设置解析事件处理器,以及如何通过遍历节点来提取或修改HTML内容。例如,可以使用`TagStart`事件捕获元素开始,`...
总的来说,基于Htmlparser的天气预报程序是利用Java技术和Htmlparser库实现的Web抓取应用,能够从网上获取并解析天气预报信息,为用户提供便捷的城市天气查询服务。它涉及到网络通信、HTML解析、数据结构化和用户...
### HTMLParser实现网页爬虫的关键知识点 #### 一、HTMLParser简介 HTMLParser是一个纯Java编写的HTML解析库,它不依赖任何其他Java库。HTMLParser的主要用途是解析和提取HTML文档中的信息。该库以其高效性和准确性...
HTMLParser是一个基于Java的库,专门用于...总的来说,`HTMLParser.zip`提供的工具和API使得Java开发者能够有效地处理HTML文档,无论这些文档是否规范,从而在各种应用场景中实现数据提取、内容处理和网页解析的需求。
"htmlparser实现从网页上抓取数据.doc"文件则很可能是一个详细的教程,指导用户如何利用HTMLParser库进行网页数据抓取。在这个教程中,可能会涵盖以下关键知识点: 1. **安装和引入HTMLParser**:首先,用户需要将...
Winista.Htmlparser.Net是一个基于C#的开源HTML解析库,它为开发者提供了一种高效且灵活的方式来处理HTML文档,尤其在需要从HTML中提取数据或者进行网页抓取时显得尤为重要。本文将深入探讨该库的核心功能、设计原理...
### 使用HttpClient和HtmlParser实现简易爬虫的知识点详解 #### 一、HttpClient与HtmlParser简介 **HttpClient简介:** HttpClient是Jakarta Commons项目中的一个重要组件,用于提供灵活且高效的HTTP协议支持。它...
这些组件可以帮助开发者更好地实现从网络获取HTML内容,然后用HTMLParser进行解析。 总之,`c#版htmlparser htmlparser.dll htmlparser源代码`提供了一个C#实现的HTML解析工具,可以帮助开发者高效地处理HTML文档,...
HTMLParser是一个基于Java的开源库,专门用于解析HTML文档。这个库允许开发者处理HTML文档,提取数据或进行格式转换,而无需关心HTML的复杂性和不规范性。在Java开发中,尤其是在网页抓取、信息提取或者自动化测试等...
此外,你还可以考虑使用HTMLParser与其他库(如Jsoup)结合,以增强解析能力,处理JavaScript生成的内容,或者进行更复杂的DOM操作。 总的来说,HTMLParser 提供了基础的HTML解析能力,适用于简单的数据抓取任务。...
【标题】基于htmlparser的ed2k搜索存放mysql的Java工具 这个项目是一个Java应用程序,其核心功能是利用htmlparser库来抓取ed2k网络中的链接和相关信息,然后将这些数据存储到MySQL数据库中。htmlparser是一个强大的...