- 浏览: 38613 次
- 性别:
- 来自: 济南
最新评论
-
fffddgx:
不过当时按照这个方法我确实实现了多线程下载。这点是确定的。
heritrix多线程探索 -
java_wzf:
我说的是只需要 在HostnameQueueAssignmen ...
heritrix多线程探索 -
java_wzf:
粗鲁的方法,要改什么东西啊,我用粗鲁的办法还是0~一个线程
heritrix多线程探索 -
fffddgx:
网上有个用elf算法重载getClassKey() 例子你可以 ...
heritrix多线程探索 -
liuxiao88:
我也按照你的方法修改HostnameQueueAssignme ...
heritrix多线程探索
先说说htmlparser的初步学习
我觉得htmlparser也不是很困难,就是处理是麻烦些,htmlparser对html节点处理的数据结构为:
解析html有3中方法
1:lexer
lexer解析html的方式更底层些,我返回的是node节点的线性序列,不能产生树形序列
2:filter
filter 解析html返回树形节点序列支持逻辑嵌套(andfilter(filter,andfilter(notfilter(),orfilter(..,..))))
比较常用的几个filter:
(1):AndFilter:相当与逻辑与,构造函数接受2个Filter(f1,f2),AndFilter(f1,f2)类似于f1&&f2
(2):HasAttributeFilter:用于提取含有指定属性的节点
(3):TagNameFilter:提取所有满足指定tag名的节点
3:visitor
其中有一个特别的 visitor:TextExtractingVisitor
此类用来提取网页中的所有文字,剔除所有标签。在有些时候比较好用。它还支持对已提取的节点的visit
用法:
//通过filter 获得NodeList NodeList gen_tr = this.getParse().parse(general_data_filter); //对已得到的NodeList采用TextExtractingVisitor方式visit //这样就实现了filter和visitor的结合使用 gen_tr.visitAllNodesWith(new TextExtractingVisitor());
注:1:我认为析取筛选网页是做搜索引擎前期最关键也是最需要耐心的工作。
2:在解析的过程中你会发现经常抛空指针异常,原因:(1):你的filter根本没有析取出节点(2):你析取出的是"/n",这个确实比较烦,一般当解析网页的时候,会经常出现很多"/n"例如:
<table>"/n"<tr>"/n"<td>"/n"text"/n"</td>"/n"</tr>"/n"</table>
下面是我解析:http://price.pcauto.com.cn/m11199/等相关的网页
这个网址中的汽车参数的代码,可能对初学者有所帮助:
提取网页内容的基类,它定义了一些提取网页内容的基本的通用的方法:
package get_infor; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import org.htmlparser.Parser; public class BaseExtractor { protected static final String NEWLINE = "\r\n"; private String outputPath; private String inputPath; private Parser parse; /** * 对图片路径进行哈希的算法,这里采用MD5算法 */ protected static final String HASH_ALGORITHM = "md5"; /** * 用于存放被处理过后的产口的图片的目录 */ private String imageDir = ""; public int extractedCount = 0; String file_name = ""; public String getOutputPath() { return outputPath; } public void setOutputPath(String outputPath) { this.outputPath = outputPath; } public String getInputPath() { return inputPath; } public void setInputPath(String inputPath) { this.inputPath = inputPath; } public Parser getParse() { return parse; } public void setParse(Parser parse) { this.parse = parse; } public String getMirrorDir() { return mirrorDir; } public void setMirrorDir(String mirrorDir) { this.mirrorDir = mirrorDir; } public String getImageDir() { return imageDir; } public void setImageDir(String imageDir) { this.imageDir = imageDir; } public static String getNEWLINE() { return NEWLINE; } public static String getHASH_ALGORITHM() { return HASH_ALGORITHM; } protected void operator() { String ip = this.getInputPath(); visit(new File(ip)); } public void visit(File dir) { if (dir.isFile()) { extract(dir.getAbsolutePath()); } else { File[] fs = dir.listFiles(); for (int i = 0; i < fs.length; i++) { if (fs[i].isFile()) { // p(fs[i].getAbsolutePath()); extract(fs[i].getAbsolutePath()); } else { visit(fs[i]); } } } } public void extract(String url) { } protected void write_file(StringBuffer sb) { try { file_name = StringUtils.filenameProcess(file_name); BufferedWriter bw = new BufferedWriter(new FileWriter(this .getOutputPath() + file_name + ".txt")); bw.write(sb.toString()); bw.flush(); p("已经处理了:"+ extractedCount+++file_name); } catch (IOException e) { e.printStackTrace(); } } protected String process(String l6_td_str) { String l6_td_str1 = l6_td_str.replaceAll("\\ ", ""); String l6_td_str2 = l6_td_str1.replaceAll("\n", ""); int index2 = l6_td_str2.lastIndexOf(">"); int index1 = l6_td_str2.indexOf("<"); if (index1 != -1 && index2 != -1) { l6_td_str2 = l6_td_str2.substring(0, index1) + l6_td_str2.substring(index2 + 1); } return l6_td_str2; } protected void p(Object o) { System.out.println(o); } }
下面的CarExtractor是对BaseExtractor的继承,重载添加了特定的方法
package get_infor; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import org.htmlparser.Node; import org.htmlparser.NodeFilter; import org.htmlparser.Parser; import org.htmlparser.filters.AndFilter; import org.htmlparser.filters.HasAttributeFilter; import org.htmlparser.filters.TagNameFilter; import org.htmlparser.tags.ImageTag; import org.htmlparser.tags.TableColumn; import org.htmlparser.tags.TableTag; import org.htmlparser.util.NodeList; import org.htmlparser.util.ParserException; import org.htmlparser.visitors.TextExtractingVisitor; public class CarExtractor extends BaseExtractor { // 析取网页内容方法 public void extract(String url) { try { String real_url = "http://"+url.substring(72,url.length()-10).replaceAll("\\\\", "/"); StringBuffer sb = new StringBuffer(); sb.append("url: "+real_url+NEWLINE); // 获得网页产品图片 String pic_src = get_pic_src(url); sb.append("pic: "+pic_src+NEWLINE); this.getParse().reset(); String general_data = this.get_general_data(url); sb.append(general_data); this.setParse(new Parser(url)); // 获得产品详细信息的过滤器 NodeFilter Attribute_filter = new AndFilter( new TagNameFilter("td"), new AndFilter( new HasAttributeFilter("class", "bor1_c1"), new HasAttributeFilter("style", "padding:5px;"))); // 设定分析器的编码方式为"gb2312" this.getParse().setEncoding("gb2312"); NodeList l1_td_list = this.getParse().parse(Attribute_filter); NodeList l2_table_list = l1_td_list.elementAt(0).getChildren(); // 获得产品的基本参数 for (int j = 1; j < l2_table_list.size(); j += 2) { TableTag l2_table = (TableTag) l2_table_list.elementAt(j); Node l4_txt = l2_table.getFirstChild().getNextSibling() .getFirstChild().getNextSibling().getFirstChild(); if (l4_txt.getClass().toString().equals( "class org.htmlparser.nodes.TextNode") && !l4_txt.getText().matches("\n")) { sb.append(process(l4_txt.getText()) + " "); } else { for (int m = 1; m < l2_table.getChildren().size(); m += 2) { NodeList l6_td_list = l2_table.getChildren().elementAt( m).getChildren().elementAt(1).getChildren() .elementAt(1).getChildren().elementAt(1) .getChildren(); for (int k = 1; k < l6_td_list.size(); k += 2) { TableColumn l6_td = (TableColumn) l6_td_list .elementAt(k); String l6_td_str = l6_td.getStringText(); l6_td_str = process(l6_td_str); if (l6_td.getAttribute("class").equals( "series_2_cs3_c1") || l6_td.getAttribute("class").equals( "series_2_cs3_c4") || l6_td.getAttribute("class").equals( "series_2_cs3_c7")) { sb.append(l6_td_str + " : "); } else if (l6_td.getAttribute("class").equals( "series_2_cs3_c2") || l6_td.getAttribute("class").equals( "series_2_cs3_c5") || l6_td.getAttribute("class").equals( "series_2_cs3_c8")) { sb.append(l6_td_str + " ; "); } } sb.append(NEWLINE); } } sb.append(NEWLINE); } // 获得产品的外设等高级参数 NodeList l2_table_list2 = l1_td_list.elementAt(1).getChildren(); for (int j = 1; j < l2_table_list2.size(); j += 2) { TableTag l2_table = (TableTag) l2_table_list2.elementAt(j); if (l2_table.getFirstChild().getNextSibling().getFirstChild().getNextSibling() != null) { Node l4_txt = l2_table.getFirstChild().getNextSibling() .getFirstChild().getNextSibling().getFirstChild(); if (l4_txt.getClass().toString().equals( "class org.htmlparser.nodes.TextNode") && !l4_txt.getText().matches("\n")) { sb.append(process(l4_txt.getText()) + " "); } else { for (int l = 1; l < l2_table.getChildren().size(); l += 2) { NodeList l4_td_list = l2_table.getChildren() .elementAt(l).getChildren(); for (int i = 1; i < l4_td_list.size(); i += 2) { TableColumn tc = (TableColumn) l4_td_list .elementAt(i).getChildren() .elementAt(1).getChildren() .elementAt(1).getChildren() .elementAt(1); sb.append(process(tc.getStringText()) + ","); } sb.append(NEWLINE); } } sb.append(NEWLINE); } } // System.out.println(sb.toString()); // 写入文件 write_file(sb); } catch (ParserException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } // 获得产品图片的src的方法 private String get_pic_src(String url) { NodeFilter pic_filter = new AndFilter(new TagNameFilter("td"), new HasAttributeFilter("class", "series_sy_intro_pic")); String imgURL = ""; String new_image_file = ""; try { this.setParse(new Parser(url)); this.getParse().setEncoding("gb2312"); NodeList pic_nodes = this.getParse().parse(pic_filter); TableColumn tc = (TableColumn) pic_nodes.elementAt(0); ImageTag it = (ImageTag) (tc.childAt(1).getChildren().elementAt(0)); imgURL = it.getImageURL(); // String fileType = imgURL.substring(imgURL // .lastIndexOf(".") + 1); //生成新的图片的文件名 new_image_file = StringUtils.encodePassword( imgURL, HASH_ALGORITHM) + ".jpg"; // imgURL = StringUtils.replace(imgURL, "+", " "); //利用miorr目录下的图片生成的新的图片 copyImage(imgURL, new_image_file); } catch (ParserException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return new_image_file; } protected boolean copyImage(String image_url, String new_image_file) { String dirs = image_url.substring(7); try { // instance the File as file_in and file_out File file_in = new File(new File("f:/"), dirs); if (file_in == null || !file_in.exists()) { file_in = new File("f:/noimage.jpg"); } File file_out = new File(new File("f:/img/"), new_image_file); FileInputStream in1 = new FileInputStream(file_in); FileOutputStream out1 = new FileOutputStream(file_out); byte[] bytes = new byte[1024]; int c; while ((c = in1.read(bytes)) != -1) out1.write(bytes, 0, c); // close in1.close(); out1.close(); return (true); // if success then return true } catch (Exception e) { e.printStackTrace(); return (false); // if fail then return false } } // 获取产品概要参数 private String get_general_data(String url){ StringBuffer general_data = new StringBuffer(); try { this.setParse(new Parser(url)); this.getParse().setEncoding("gb2312"); NodeFilter general_data_filter = new AndFilter(new TagNameFilter("table"),new HasAttributeFilter("class","series_sy_intro_txt")); NodeFilter price_filter = new AndFilter(new TagNameFilter("td"),new HasAttributeFilter("class","f18b")); NodeList general_data_list = this.getParse().parse(general_data_filter); NodeList gen_tr = general_data_list.elementAt(0).getChildren(); gen_tr.visitAllNodesWith(new TextExtractingVisitor()); String str = process(gen_tr.asString().replaceAll("\\s", "")); // 获得文件名字 file_name= get_title(str); this.getParse().reset(); NodeList price_td = this.getParse().parse(price_filter); TableColumn tc = (TableColumn)price_td.elementAt(0); String price = tc.getStringText(); str = "概要参数:"+ str + NEWLINE +"厂家指导价: "+price+NEWLINE; general_data.append(str); } catch (ParserException e) { e.printStackTrace(); } return general_data.toString(); } private String get_title(String str) { int index1,index2,index3,index4,index5; index1 = str.indexOf("生产厂商:")+5; index2 = str.indexOf("所属:"); index3 = str.indexOf("上市时间:"); index4 = str.indexOf("型 号:")+5; index5 = str.indexOf("车 型:"); String bland = str.substring(index1,index2); String type = str.substring(index2+3,index3); String name = str.substring(index4,index5); return bland+"_"+type+""+name; } public static void main(String args[]) { CarExtractor ex = new CarExtractor(); ex .setInputPath("F:/Workspaces/MyEclipse 7.1/heritrix/jobs/may2-20090501055518750/mirror/price.pcauto.com.cn"); ex.setOutputPath("F:/job/"); ex.get_general_data("F:/Workspaces/MyEclipse 7.1/heritrix/jobs/may2-20090501055518750/mirror/price.pcauto.com.cn/m157/index.html"); ex.operator(); // ex.extract("F:/Workspaces/MyEclipse 7.1/heritrix/jobs/may2-20090501055518750/mirror/price.pcauto.com.cn/m157/index.html"); } }
中间 会用到StringUtils这个类,它的主要作用是对图片名称的md5编码,形成独一无二的名字
package get_infor; import java.security.MessageDigest; public class StringUtils { public static String trim(String line) { String result = line.trim(); while (result.startsWith(" ")) { result = result.substring(1); } while (result.endsWith(" ")) { result = result.substring(0, result.length() - 1); } return result; } public static String filenameProcess(String name) { String result = name.trim(); result = result.replaceAll("\\\\", "_"); result = result.replaceAll("/", "_"); result = result.replaceAll("\\*", " "); return result; } public static String encodePassword(String password, String algorithm) { byte[] unencodedPassword = password.getBytes(); MessageDigest md = null; try { // first create an instance, given the provider md = MessageDigest.getInstance(algorithm); } catch (Exception e) { return password; } md.reset(); // call the update method one or more times // (useful when you don't know the size of your data, eg. stream) md.update(unencodedPassword); // now calculate the hash byte[] encodedPassword = md.digest(); StringBuffer buf = new StringBuffer(); for (int i = 0; i < encodedPassword.length; i++) { if ((encodedPassword[i] & 0xff) < 0x10) { buf.append("0"); } buf.append(Long.toString(encodedPassword[i] & 0xff, 16)); } return buf.toString(); } public static final String replace(String line, String oldString, String newString) { if (line == null) { return null; } int i = 0; if ((i = line.indexOf(oldString, i)) >= 0) { char[] line2 = line.toCharArray(); char[] newString2 = newString.toCharArray(); int oLength = oldString.length(); StringBuffer buf = new StringBuffer(line2.length); buf.append(line2, 0, i).append(newString2); i += oLength; int j = i; while ((i = line.indexOf(oldString, i)) > 0) { buf.append(line2, j, i - j).append(newString2); i += oLength; j = i; } buf.append(line2, j, line2.length - j); return buf.toString(); } return line; } }
运行CarExtractor的main方法即可实现对INputPath目录下的所有已下网页的处理析取
运行后会出现像下面这种格式的5000多个txt文件
pic: bf66b8100173abc02ccbd96181df141a.jpg
概要参数:型 号:凯雷德外交官2驱车 型:SUV/CRV/CUV生产厂商:ECB工厂所属:[凯雷德]上市时间:2008最近更新:2008.06.27查二手车报价外形尺寸(长/宽/高):0/0/0油耗:0.0L查看实际油耗优 点:非常豪华,具有与生俱来的王者气势缺 点:油耗偏高
厂家指导价: 136.0万
凯雷德 外交官 2驱-基本资料
车型名称 : 凯雷德 外交官 2驱 ; 车体结构 : SUV/CRV/CUV ; 豪华级别 : 豪华型 ;
凯雷德 外交官 2驱-引擎参数
标准引擎 : V型8缸/6.2升/VVT可变进排气门正时/ETC电子节气门控制 ; 标准变速器 : 手自一体 6档 ; 标准排量 : 6200 cc ;
气门数 : 32 ; 最大功率 : 301/5700 KW/rpm ; 最大扭矩 : 565/4400 N?m/rpm ;
燃油系统 : 电子燃油喷射式 ; 理论油耗 : 升/百公里 ; 最高时速 : km/h ;
加速时间 : 秒(0-100km/h) ; 排放标准 : 欧Ⅳ标准 ; : ;
凯雷德 外交官 2驱-转向/悬挂/轮胎
驱动方式 : 前置后驱 ; 制动方式 : 碟/碟(前/后) ; 转向助力 : 助力转向式 ;
悬挂方式 : ; 轮毂尺寸 : ; 轮胎 : ;
尺寸和重量
车身重量 : kg ; 轴距 : mm ; 轮距 : mm(前/后) ;
全车长度 : mm ; 车身宽度 : mm ; 车身高度 : mm ;
通过性
最小转弯半径 : m ; 最小离地间隙 : mm ; 最大爬坡度 : % ;
接近角 : ° ; 离去角 : ° ; : ;
货舱容积
行李舱容积 : L ; 油箱容积 : L ; 标准座位数 : ;
外观/内饰
舒适性配置
车辆安全/防盗配置
其他功能配置
毕竟我也是菜鸟,在设计过程中也遇到了很多困难,但是都一一克服,我说的有什么不对的地方,欢迎大家指正。谢谢
以上的3个类在设计过程中参考了《lucene+heritrix 开发自己的搜索引擎》
发表评论
-
毕业设计总结
2009-07-01 12:08 1299经过一个多月的努力,我的搜索引擎终于完成了,实现了简单搜索,在 ... -
搜索提示功能实现
2009-05-30 01:42 2261搜索提示功能主要依靠的是ajax技术,本系统用的是ajax开源 ... -
lucene关键字高亮显示
2009-05-24 22:17 2957关键字高亮显示也就是在页面显示时,事先对要显示的内容处理,抽取 ... -
lucene整合struts2,搜索引擎的初步实现
2009-05-24 01:22 2989构思时这样:采用3层架构 表示层:有3个jsp页面。 ... -
lucene索引
2009-05-20 22:47 1809说是第8天,其实就是起个计数作用最近太懒了 提取出了网页,并 ... -
htmlparser初体验
2009-05-02 23:32 1959昨天晚上完成了网页的下载,暂时不用和heritrix打交道了, ... -
heritrix使用经验
2009-04-30 16:24 20651:create based on existing job ... -
heritrix多线程探索
2009-04-28 21:00 3051上午说的那个方法经过试验是不起作用的。 按照上面说的配置后开 ... -
heritrix扩展,多线程抓取网页
2009-04-28 15:06 3583由于下载速度太慢,打算重载QueueAssignmentPol ... -
爬虫问题
2009-04-27 22:59 2068今天爬虫爬了一天,速度出奇的慢,始终是单线程在运作,最后也没有 ... -
heritrix种子选取,与扩展抓取
2009-04-26 22:30 3293搜索引擎首先要用爬虫把网页爬下来,我用Heritrix,选择H ... -
毕设进行时--第1天(垂直搜索引擎的设计与实现)
2009-04-23 18:19 1028今天毕设正式开始,开了javaeye的博客记录下 我的毕设题 ...
相关推荐
### HtmlParser提取网页信息的设计与实现 #### 一、引言 随着互联网的快速发展和信息量的爆炸式增长,从海量网页数据中提取有价值的信息变得日益重要。这不仅有助于提高信息检索的效率,还能为自动化的数据分析...
最后,我们使用 InputStreamReader 对象来读取网页的内容,并使用 HTMLParser 来解析网页。 HTMLParser 是一个功能强大且灵活的类库,用于解析和处理网页内容。它提供了多种使用方式和机制,适合不同的应用场景。
总结来说,HTMLParser 提供了一个高效且结构化的接口来解析HTML文档,结合正则表达式的清理,我们可以有效地提取网页的正文和标题。在进行这样的操作时,需要注意正确处理各种HTML标签和结构,以确保提取到的信息...
在本研究中,我们将重点探讨如何使用HTMLParser来提取网页中的超链接。 **2.2 开发环境的搭建** 为了使用HTMLParser进行网页超链接的提取,首先需要搭建合适的开发环境。本研究中选择的开发环境包括: - **...
本文主要介绍了如何利用HttpClient与HTMLParser这两种技术来实现网页正文的提取。文章首先阐述了互联网信息飞速增长的背景下,网页数据提取的重要性,以及自动化的网页抓取与分析对于科研、工程和商业活动的意义。...
Winista.HtmlParser是一个轻量级的HTML解析器,适合用于快速提取网页内容,尤其是在开发搜索引擎或者网页爬虫时非常有用。这个小实例包含了必要的源代码、使用的dll文件以及一个CHM帮助文档,旨在帮助开发者快速理解...
总之,C#结合正则表达式和HTMLParser为我们提供了一种强大的手段,可以从网页中提取所需信息。尽管这个实例中代码的可读性可能不高,但通过学习正则表达式和HTML解析库的基本用法,我们可以自己构建类似的解决方案,...
使用htmlparser制作的网页爬虫例题
它提供了对HTML内容的结构化访问,使得开发者能够方便地处理和提取网页数据。本篇将详细阐述HTMLParser的使用方法、功能以及提供的相关资源。 首先,`HTMLParser-2.0-SNAPSHOT-doc.zip`包含了HTMLParser的使用文档...
比如,你可以使用它来提取网页上的特定数据,如价格、评论、链接等;也可以用于验证网页的结构是否符合预期,或者在不影响页面展示的情况下替换或添加HTML元素。 6. 扩展性:HTMLParser提供了丰富的API,允许开发者...
### JAVA HtmlParser 使用实例详解 在Java开发过程中,解析HTML文档是一项常见的需求,尤其是在处理Web爬虫、数据抓取等应用场景时。`HtmlParser`库为开发者提供了一种简便的方式来解析HTML文档,并从中提取所需的...
实际应用中,HTMLParser常与网络请求库(如Apache HttpClient或OkHttp)结合使用,以获取远程网页内容,再进行后续的解析操作。同时,为了提高代码的可维护性和复用性,建议封装自己的数据抓取和处理模块。
这个库使得开发者能够方便地从HTML中提取数据,处理DOM(文档对象模型),以及与网页内容进行交互。本项目名为"HTMLParser.net源代码HTMLParser.net使用demo",显然是一个包含示例代码的压缩包,用于展示如何在实际...
本文将详细讲解如何使用Java的htmlparser库实现网页抓取,并探讨其核心概念和用法。 首先,从给定的代码示例中可以看出,这是一个简单的Java程序,用于从指定的URL抓取HTML内容并将其保存到本地文件。这个程序的...
例如,你可以使用HTMLParser解析整个网页,然后通过XPath找到特定的元素,如所有的链接(`<a>`标签)。这在进行网络爬虫开发时非常有用,可以提取出网页中的所有链接,进行进一步的分析或者访问。 HTMLParser库还...
这使得HTMLParser不仅可以用于基本的标签提取,还能用于更复杂的网页数据抓取和分析。 总的来说,HTMLParser是一个功能丰富的HTML解析工具,对于需要处理HTML的Java开发者来说,它是一个强大且灵活的解决方案。通过...