[置顶] 网络爬虫---htmlparser

时间:2023-02-04 16:23:12

package parser;

import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.FileWriter;

import java.io.IOException;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.net.MalformedURLException;

import java.net.URL;

/**

 * 基本能实现网页抓取,不过要手动输入URL 将整个html内容保存到指定文件

 * 

 * @author chenguoyong

 * 

 */

public class ScrubSelectedWeb {

private final static String CRLF = System.getProperty("line.separator");

/**

 * @param args

 */

public static void main(String[] args) {

try {

URL ur = new URL("http://10.249.187.199:8083/injs100/");

InputStream instr = ur.openStream();

String s, str;

BufferedReader in = new BufferedReader(new InputStreamReader(instr));

StringBuffer sb = new StringBuffer();

BufferedWriter out = new BufferedWriter(new FileWriter(

"D:/outPut.txt"));

while ((s = in.readLine()) != null) {

sb.append(s + CRLF);

}

System.out.println(sb);

str = new String(sb);

out.write(str);

out.close();

in.close();

} catch (MalformedURLException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

}

}

基本能实现网页抓取,不过要手动输入URL,此外没有重构。只是一个简单的思路。

1.htmlparser 使用

htmlparser是一个纯的java写的html解析的库,htmlparser不依赖于其它的java库,htmlparser主要用于改造 或提取htmlhtmlparser能超高速解析html,而且不会出错。毫不夸张地说,htmlparser就是目前最好的html解 析和分析的工具。无论你是想抓取网页数据还是改造html的内容,用了htmlparser绝对会忍不住称赞。由于htmlparser 结构设计精良,所以扩展htmlparser 非常便利。

Htmlparser中文论坛.  http://bbs.hexiao.cn/thread.php?fid=6

Constructor Summary

Parser() 

Parser(URLConnection connection) 
          Construct a parser using the provided URLConnection.

Method:

static Parser createParser(String html, String charset) 
          Creates the parser on an input string.

 void visitAllNodesWith(NodeVisitor visitor) 
          Apply the given visitor to the current page.

HtmlPage(Parser parser)

 NodeList

getBody() 
           

 TableTag[]

getTables() 
           

 String

getTitle() 
           

 void

setTitle(String title) 
           

 void

visitTag(Tag tag) 
          Called for each Tag visited.

 

Constructor Summary

NodeList() 
           

NodeList(Node node) 
          Create a one element node list.

  NodeList extractAllNodesThatMatch(NodeFilter filter) 
          Filter the list with the given filter non-recursively.  

NodeList extractAllNodesThatMatch(NodeFilter filter, boolean recursive) 
          Filter the list with the given filter.

 Node elementAt(int i)

1. html代码里面所有的链接地址和链接名称

package parser;

import org.htmlparser.Parser;

import org.htmlparser.Node;

import org.htmlparser.NodeFilter;

import org.htmlparser.Parser;

import org.htmlparser.filters.TagNameFilter;

import org.htmlparser.tags.LinkTag;

import org.htmlparser.tags.TableTag;

import org.htmlparser.util.NodeList;

import org.htmlparser.util.ParserException;

import org.htmlparser.visitors.HtmlPage;

/**

 * htmlparser取得一段html代码里面所有的链接地址和链接名称

 * 

 * @author chenguoyong

 * 

 */

public class Testhtmlparser {

/**

 * @param args

 */

public static void main(String[] args) {

String htmlcode = "<HTML><HEAD><TITLE>AAA</TITLE></HEAD><BODY>"

+ "<a href='http://topic.csdn.net/u/20080522/14/0ff402ef-c382-499a-8213-ba6b2f550425.html'>连接1</a>"

+ "<a href='http://topic.csdn.net'>连接2</a></BODY></HTML>";

// 创建Parser对象根据传给字符串和指定的编码

Parser parser = Parser.createParser(htmlcode, "GBK");

// 创建HtmlPage对象HtmlPage(Parser parser)

HtmlPage page = new HtmlPage(parser);

try {

// HtmlPage extends visitor,Apply the given visitor to the current

// page.

parser.visitAllNodesWith(page);

} catch (ParserException e1) {

e1 = null;

}

// 所有的节点

NodeList nodelist = page.getBody();

// 建立一个节点filter用于过滤节点

NodeFilter filter = new TagNameFilter("A");

// 得到所有过滤后,想要的节点

nodelist = nodelist.extractAllNodesThatMatch(filter, true);

for (int i = 0; i < nodelist.size(); i++) {

LinkTag link = (LinkTag) nodelist.elementAt(i);

// 链接地址

System.out.println(link.getAttribute("href") + "\n");

// 链接名称

System.out.println(link.getStringText());

}

}

}

结果如下:

http://topic.csdn.net/u/20080522/14/0ff402ef-c382-499a-8213-ba6b2f550425.html

连接1

http://topic.csdn.net

连接2

2. 使用HtmlParser抓去网页内容

package parser;

import org.htmlparser.Parser;

import org.htmlparser.beans.StringBean;

import org.htmlparser.filters.NodeClassFilter;

import org.htmlparser.parserapplications.StringExtractor;

import org.htmlparser.tags.BodyTag;

import org.htmlparser.util.NodeList;

import org.htmlparser.util.ParserException;

/**

 * 使用HtmlParser抓去网页内容要抓去页面的内容最方便的方法就是使用StringBean. 里面有几个控制页面内容的几个参数.

 * 在后面的代码中会有说明. Htmlparser包中还有一个示例StringExtractor 里面有个直接得到内容的方法,

 * 其中也是使用了StringBean . 另外直接解析Parser的每个标签也可以的.

 * 

 * @author chenguoyong

 * 

 */

public class GetContent {

public void getContentUsingStringBean(String url) {

StringBean sb = new StringBean();

sb.setLinks(true); // 是否显示web页面的连接(Links)

// 为了取得页面的整洁美观一般设置上面两项为true , 如果要保持页面的原有格式如代码页面的空格缩进 可以设置为false

sb.setCollapse(true); // 如果是true的话把一系列空白字符用一个字符替代.

sb.setReplaceNonBreakingSpaces(true);// If true regular space

sb

.setURL("http://www.blogjava.net/51AOP/archive/2006/07/19/59064.html");

System.out.println("The Content is :\n" + sb.getStrings());

}

public void getContentUsingStringExtractor(String url, boolean link) {

// StringExtractor内部机制和上面的一样.做了一下包装

StringExtractor se = new StringExtractor(url);

String text = null;

try {

text = se.extractStrings(link);

System.out.println("The content is :\n" + text);

} catch (ParserException e) {

e.printStackTrace();

}

}

public void getContentUsingParser(String url) {

NodeList nl;

try {

Parser p = new Parser(url);

nl = p.parse(new NodeClassFilter(BodyTag.class));

BodyTag bt = (BodyTag) nl.elementAt(0);

System.out.println(bt.toPlainTextString()); // 保留原来的内容格式包含js代码

} catch (ParserException e) {

e.printStackTrace();

}

}

/**

 * @param args

 */

public static void main(String[] args) {

String url = "http://www.blogjava.net/51AOP/archive/2006/07/19/59064.html";

//new GetContent().getContentUsingParser(url);

//--------------------------------------------------

new GetContent().getContentUsingStringBean(url);

}

}

3.将整个html内容保存到指定文件

package parser;

import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.FileWriter;

import java.io.IOException;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.net.MalformedURLException;

import java.net.URL;

/**

 * 基本能实现网页抓取,不过要手动输入URL 将整个html内容保存到指定文件

 * 

 * @author chenguoyong

 * 

 */

public class ScrubSelectedWeb {

private final static String CRLF = System.getProperty("line.separator");

/**

 * @param args

 */

public static void main(String[] args) {

try {

URL ur = new URL("http://www.google.cn/");

InputStream instr = ur.openStream();

String s, str;

BufferedReader in = new BufferedReader(new InputStreamReader(instr));

StringBuffer sb = new StringBuffer();

BufferedWriter out = new BufferedWriter(new FileWriter(

"D:/outPut.txt"));

while ((s = in.readLine()) != null) {

sb.append(s + CRLF);

}

System.out.println(sb);

str = new String(sb);

out.write(str);

out.close();

in.close();

} catch (MalformedURLException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

}

}

4利用htmlparser提取网页纯文本的例子

package parser;

import org.htmlparser.Node;

import org.htmlparser.NodeFilter;

import org.htmlparser.Parser;

import org.htmlparser.filters.TagNameFilter;

import org.htmlparser.tags.TableTag;

import org.htmlparser.util.NodeList;

/**

 * 标题:利用htmlparser提取网页纯文本的例子

 */

public class TestHTMLParser2 {

/**

 * 读取目标html内容

 *

 */

public static void testHtml() {

try {

String sCurrentLine;

String sTotalString;

sCurrentLine = "";

sTotalString = "";

java.io.InputStream l_urlStream;

java.net.URL l_url = new java.net.URL(

"http://10.249.187.199:8083/injs100/");

java.net.HttpURLConnection l_connection = (java.net.HttpURLConnection) l_url

.openConnection();

l_connection.connect();

l_urlStream = l_connection.getInputStream();

java.io.BufferedReader l_reader = new java.io.BufferedReader(

new java.io.InputStreamReader(l_urlStream));

while ((sCurrentLine = l_reader.readLine()) != null) {

sTotalString += sCurrentLine + "\r\n";

}

String testText = extractText(sTotalString);

} catch (Exception e) {

e.printStackTrace();

}

}

    /**

     * 抽取纯文本信息

     * @param inputHtmlhtml文本

     * @return

     * @throws Exception

     */

public static String extractText(String inputHtml) throws Exception {

StringBuffer text = new StringBuffer();

Parser parser = Parser.createParser(new String(inputHtml.getBytes(),

"GBK"), "GBK");

// 遍历所有的节点

NodeList nodes = parser.extractAllNodesThatMatch(new NodeFilter() {

public boolean accept(Node node) {

return true;

}

});

System.out.println(nodes.size());

for (int i = 0; i < nodes.size(); i++) {

Node nodet = nodes.elementAt(i);

//字符串的代表性节点:节点的描述

text.append(new String(nodet.toPlainTextString().getBytes("GBK"))

+ "\r\n");

}

return text.toString();

}

    /**

     *  读取文件的方式/utl 来分析内容. filePath也可以是一个Url.

     * @param resource :文件/Url

     * @throws Exception

     */

public static void test5(String resource) throws Exception {

Parser myParser = new Parser(resource);

myParser.setEncoding("GBK");

String filterStr = "table";

NodeFilter filter = new TagNameFilter(filterStr);

NodeList nodeList = myParser.extractAllNodesThatMatch(filter);

/*for(int i=0;i<nodeList.size();i++)

{

TableTag tabletag = (TableTag) nodeList.elementAt(i);

//标签名称

System.out.println(tabletag.getTagName());

System.out.println(tabletag.getText());

}*/

TableTag tabletag = (TableTag) nodeList.elementAt(1);

}

public static void main(String[] args) throws Exception {

test5("http://10.249.187.199:8083/injs100/");

//testHtml();

}

}

5.html解析table

package parser;

import org.apache.log4j.Logger;

import org.htmlparser.NodeFilter;

import org.htmlparser.Parser;

import org.htmlparser.filters.NodeClassFilter;

import org.htmlparser.filters.OrFilter;

import org.htmlparser.filters.TagNameFilter;

import org.htmlparser.tags.TableColumn;

import org.htmlparser.tags.TableRow;

import org.htmlparser.tags.TableTag;

import org.htmlparser.util.NodeList;

import org.htmlparser.util.ParserException;

import junit.framework.TestCase;

public class ParserTestCase extends TestCase {

private static final Logger logger = Logger.getLogger(ParserTestCase.class);

public ParserTestCase(String name) {

super(name);

}

/**

 * 测试对<table>

 * <tr>

 * <td></td>

 * </tr>

 * </table>的解析

 */

public void testTable() {

Parser myParser;

NodeList nodeList = null;

myParser = Parser

.createParser(

"<body> "

+ "<table id=table1′ >"

+ "<tr id='tro1'><td>1-11</td><td>1-12</td><td>1-13</td></tr>"

+ "<tr id='tro2'><td>1-21</td><td>1-22</td><td>1-23</td></tr>"

+ "<tr id='tro3'><td>1-31</td><td>1-32</td><td>1-33</td></tr></table>"

+ "<table id=table2′ >"

+ "<tr id='tro4'><td>2-11</td><td>2-12</td><td>2-13</td></tr>"

+ "<tr id='tro5'><td>2-21</td><td>2-22</td><td>2-23</td></tr>"

+ "<tr id='tro6'><td>2-31</td><td>2-32</td><td>2-33</td></tr></table>"

+ "</body>", "GBK");

NodeFilter tableFilter = new NodeClassFilter(TableTag.class);

OrFilter lastFilter = new OrFilter();

lastFilter.setPredicates(new NodeFilter[] { tableFilter });

try {

nodeList = myParser.parse(lastFilter);

for (int i = 0; i <= nodeList.size(); i++) {

if (nodeList.elementAt(i) instanceof TableTag) {

TableTag tag = (TableTag) nodeList.elementAt(i);

TableRow[] rows = tag.getRows();

for (int j = 0; j < rows.length; j++) {

TableRow tr = (TableRow) rows[j];

System.out.println(tr.getAttribute("id"));

if (tr.getAttribute("id").equalsIgnoreCase("tro1")) {

TableColumn[] td = tr.getColumns();

for (int k = 0; k < td.length; k++) {

// logger.fatal("<td>" +

// td[k].toPlainTextString());

System.out.println("<td>"

+ td[k].toPlainTextString());

}

}

}

}

}

} catch (ParserException e) {

e.printStackTrace();

}

}

/**

 * 得到目标数据

 * 

 * @param url:目标url

 * @throws Exception

 */

public static void getDatabyUrl(String url) throws Exception {

Parser myParser = new Parser(url);

NodeList nodeList = null;

myParser.setEncoding("gb2312");

NodeFilter tableFilter = new NodeClassFilter(TableTag.class);

OrFilter lastFilter = new OrFilter();

lastFilter.setPredicates(new NodeFilter[] { tableFilter });

try {

nodeList = myParser.parse(lastFilter);

// 可以从数据tablesize:19-21开始到结束

for (int i = 15; i <= nodeList.size(); i++) {

if (nodeList.elementAt(i) instanceof TableTag) {

TableTag tag = (TableTag) nodeList.elementAt(i);

TableRow[] rows = tag.getRows();

for (int j = 0; j < rows.length; j++) {

TableRow tr = (TableRow) rows[j];

if (tr.getAttribute("id") != null

&& tr.getAttribute("id").equalsIgnoreCase(

"tr02")) {

TableColumn[] td = tr.getColumns();

// 对不起,没有你要查询的记录!

if (td.length == 1) {

System.out.println("对不起,没有你要查询的记录");

} else {

for (int k = 0; k < td.length; k++) {

System.out.println("<td>内容:"

+ td[k].toPlainTextString().trim());

}

}

}

}

}

}

} catch (ParserException e) {

e.printStackTrace();

}

}

/**

 * 测试已经得出有数据时table:22个,没有数据时table:19

 * 

 * @param args

 */

public static void main(String[] args) {

try {

// getDatabyUrl("http://gd.12530.com/user/querytonebytype.do?field=tonecode&condition=619505000000008942&type=1006&pkValue=619505000000008942");

getDatabyUrl("http://gd.12530.com/user/querytonebytype.do?field=tonecode&condition=619272000000001712&type=1006&pkValue=619272000000001712");

} catch (Exception e) {

e.printStackTrace();

}

}

}

6.html解析常用

package com.jscud.test;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;

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.nodes.TextNode;
import org.htmlparser.tags.LinkTag;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;
import org.htmlparser.visitors.HtmlPage;
import org.htmlparser.visitors.TextExtractingVisitor;

import com.jscud.util.LogMan; //一个日志记录类

/**
演示了Html Parse的应用.

* @author scud http://www.jscud.com (http://www.jscud.com/)
*/

public class ParseHtmlTest
{

public static void main(String[] args) throws Exception
{
String aFile = "e:/jscud/temp/test.htm";

String content = readTextFile(aFile, "GBK");

test1(content);
System.out.println("====================================");

test2(content);
System.out.println("====================================");

test3(content);
System.out.println("====================================");

test4(content);
System.out.println("====================================");

test5(aFile);
System.out.println("====================================");

//访问外部资源,相对慢
test5("http://www.jscud.com (http://www.jscud.com/)"); 
System.out.println("====================================");

}

/**
读取文件的方式来分析内容.
* filePath也可以是一个Url.

* @param resource 文件/Url
*/
public static void test5(String resource) throws Exception
{
Parser myParser = new Parser(resource);

//设置编码
myParser.setEncoding("GBK");

HtmlPage visitor = new HtmlPage(myParser);

myParser.visitAllNodesWith(visitor);

String textInPage = visitor.getTitle();

System.out.println(textInPage);
}

/**
按页面方式处理.对一个标准的Html页面,推荐使用此种方式.
*/
public static void test4(String content) throws Exception
{
Parser myParser;
myParser = Parser.createParser(content, "GBK");

HtmlPage visitor = new HtmlPage(myParser);

myParser.visitAllNodesWith(visitor);

String textInPage = visitor.getTitle();

System.out.println(textInPage);
}

/**
利用Visitor模式解析html页面.
*
小优点:翻译了<>等符号 
缺点:好多空格,无法提取link

*/
public static void test3(String content) throws Exception
{
Parser myParser;
myParser = Parser.createParser(content, "GBK");

TextExtractingVisitor visitor = new TextExtractingVisitor();

myParser.visitAllNodesWith(visitor);

String textInPage = visitor.getExtractedText();

System.out.println(textInPage);
}

/**
得到普通文本和链接的内容.

使用了过滤条件.
*/
public static void test2(String content) throws ParserException
{
Parser myParser;
NodeList nodeList = null;

myParser = Parser.createParser(content, "GBK");

NodeFilter textFilter = new NodeClassFilter(TextNode.class);
NodeFilter linkFilter = new NodeClassFilter(LinkTag.class);

//暂时不处理 meta
//NodeFilter metaFilter = new NodeClassFilter(MetaTag.class);

OrFilter lastFilter = new OrFilter();
lastFilter.setPredicates(new NodeFilter[] { textFilter, linkFilter });

nodeList = myParser.parse(lastFilter);

Node[] nodes = nodeList.toNodeArray();

for (int i = 0; i < nodes.length; i++)
{
Node anode = (Node) nodes[i];

String line = "";
if (anode instanceof TextNode)
{
TextNode textnode = (TextNode) anode;
//line = textnode.toPlainTextString().trim();
line = textnode.getText();
}
else if (anode instanceof LinkTag)
{
LinkTag linknode = (LinkTag) anode;

line = linknode.getLink();
//@todo ("") 过滤jsp标签:可以自己实现这个函数
//line = StringFunc.replace(line, "<%.*%>", "");
}

if (isTrimEmpty(line))
continue;

System.out.println(line);
}
}

/**
解析普通文本节点.

* @param content
* @throws ParserException
*/
public static void test1(String content) throws ParserException
{
Parser myParser;
Node[] nodes = null;

myParser = Parser.createParser(content, null);

nodes = myParser.extractAllNodesThatAre(TextNode.class); //exception could be thrown here

for (int i = 0; i < nodes.length; i++)
{
TextNode textnode = (TextNode) nodes[i];
String line = textnode.toPlainTextString().trim();
if (line.equals(""))
continue;
System.out.println(line);
}

}

/**
读取一个文件到字符串里.

* @param sFileName 文件名
* @param sEncode String
* @return 文件内容
*/
public static String readTextFile(String sFileName, String sEncode)
{
StringBuffer sbStr = new StringBuffer();

try
{
File ff = new File(sFileName);
InputStreamReader read = new InputStreamReader(new FileInputStream(ff),
sEncode);
BufferedReader ins = new BufferedReader(read);

String dataLine = "";
while (null != (dataLine = ins.readLine()))
{
sbStr.append(dataLine);
sbStr.append("\r\n");
}

ins.close();
}
catch (Exception e)
{
LogMan.error("read Text File Error", e);
}

return sbStr.toString();
}

/**
去掉左右空格后字符串是否为空
* @param astr String
* @return boolean
*/
public static boolean isTrimEmpty(String astr)
{
if ((null == astr) || (astr.length() == 0))
{
return true;
}
if (isBlank(astr.trim()))
{
return true;
}
return false;
}

/**
字符串是否为空:null或者长度为0.
* @param astr 源字符串.
* @return boolean
*/
public static boolean isBlank(String astr)
{
if ((null == astr) || (astr.length() == 0))
{
return true;
}
else
{
return false;
}
}

}

2.使用 HttpClient 和 HtmlParser 实现简易爬虫

 本小结简单的介绍一下 HttpClinet 和 HtmlParser 两个开源的项目,以及他们的网站和提供下载的地址。

  HttpClient 简介

 HTTP 协议是现在的因特网最重要的协议之一。除了 WEB 浏览器之外, WEB 服务,基于网络的应用程序以及日益增长的网络计算不断扩展着 HTTP 协议的角色,使得越来越多的应用程序需要 HTTP 协议的支持。虽然 JAVA 类库 .net 包提供了基本功能, 来使用 HTTP 协议访问网络资源,但是其灵活性和功能远不能满足很多应用程序的需要。而 Jakarta Commons HttpClient 组件寻求提供更为灵活,更加高效的 HTTP 协议支持,简化基于 HTTP 协议的应用程序的创建。 HttpClient 提供了很多的特性,支持最新的 HTTP 标准,可以访问这里了解更多关于 HttpClinet 的详细信息。目前有很多的开源项目都用到了 HttpClient 提供的 HTTP功能,登陆网址可以查看这些项目。本文中使用 HttpClinet 提供的类库来访问和下载 Internet上面的网页,在后续部分会详细介绍到其提供的两种请求网络资源的方法: Get 请求和 Post 请求。Apatche 提供免费的 HTTPClien t源码和 JAR 包下载,可以登陆这里 下载最新的HttpClient 组件。笔者使用的是 HttpClient3.1

  HtmlParser 简介

   当今的 Internet 上面有数亿记的网页,越来越多应用程序将这些网页作为分析和处理的数据对象。这些网页多为半结构化的文本,有着大量的标签和嵌套的结构。当我们自己开发一 些处理网页的应用程序时,会想到要开发一个单独的网页解析器,这一部分的工作必定需要付出相当的精力和时间。事实上,做为 JAVA 应用程序开发者, HtmlParser 为其提供了强大而灵活易用的开源类库,大大节省了写一个网页解析器的开销。 HtmlParser 是 http://sourceforge.net 上活跃的一个开源项目,它提供了线性和嵌套两种方式来解析网页,主要用于 html 网页的转换(Transformation) 以及网页内容的抽取 (Extraction)HtmlParser 有如下一些易于使用的特性:过滤器 (Filters),访问者模式 (Visitors),处理自定义标签以及易于使用的 JavaBeans。正如 HtmlParser 首页所说:它是一个快速,健壮以及严格测试过的组件;以它设计的简洁,程序运行的速度以及处理 Internet 上真实网页的能力吸引着越来越多的开发者。 本文中就是利用HtmlParser 里提取网页里的链接,实现简易爬虫里的关键部分。HtmlParser 最新的版本是HtmlParser1.6,可以登陆这里下载其源码、 API 参考文档以及 JAR 包。


 简单强大的 StringBean 

 如果你想要网页中去掉所有的标签后剩下的文本,那就是用 StringBean 吧。以下简单的代码可以帮你解决这样的问题:

  清单5

  StringBean sb = new StringBean();

  sb.setLinks(false);//设置结果中去点链接

  sb.setURL(url);//设置你所需要滤掉网页标签的页面 url

  System.out.println(sb.getStrings());//打印结果

  HtmlParser 提供了强大的类库来处理网页,由于本文旨在简单的介绍,因此只是将与笔者后续爬虫部分有关的关键类库进行了示例说明。感兴趣的读者可以专门来研究一下 HtmlParser 更为强大的类库。

  简易爬虫的实现

  HttpClient 提供了便利的 HTTP 协议访问,使得我们可以很容易的得到某个网页的源码并保存在本地;HtmlParser 提供了如此简便灵巧的类库,可以从网页中便捷的提取出指向其他网页的超链接。笔者结合这两个开源包,构建了一个简易的网络爬虫。

  爬虫 (Crawler) 原理

   学过数据结构的读者都知道有向图这种数据结构。如下图所示,如果将网页看成是图中的某一个节点,而将网页中指向其他网页的链接看成是这个节点指向其他节 点的边,那么我们很容易将整个 Internet 上的网页建模成一个有向图。理论上,通过遍历算法遍历该图,可以访问到Internet 上的几乎所有的网页。最简单的遍历就是宽度优先以及深度优先。以下笔者实现的简易爬虫就是使用了宽度优先的爬行策略。

  图 2. 网页关系的建模图

  简易爬虫实现流程

  在看简易爬虫的实现代码之前,先介绍一下简易爬虫爬取网页的流程。

 图 3. 爬虫流程图

各个类的源码以及说明

  对应上面的流程图,简易爬虫由下面几个类组成,各个类职责如下:

  Crawler.java:爬虫的主方法入口所在的类,实现爬取的主要流程。

  LinkDb.java:用来保存已经访问的 url 和待爬取的 url 的类,提供url出对入队操作。

  Queue.java: 实现了一个简单的队列,在 LinkDb.java 中使用了此类。

  FileDownloader.java:用来下载 url 所指向的网页。

  HtmlParserTool.java: 用来抽取出网页中的链接。

  LinkFilter.java:一个接口,实现其 accept() 方法用来对抽取的链接进行过滤。 

  下面是各个类的源码,代码中的注释有比较详细的说明。

3.Htmlparser汇总说明

关键字: htmlparser 

    需要做一个垂直搜索引擎,比较了nekohtmlhtmlparser 的功能,尽管nekohtml在容错性、性能等方面的口碑好像比htmlparser好(htmlunit也用的是nekohtml),但感觉 nekohtml的测试用例和文档都比htmlparser都少,而且htmlparser基本上能够满足垂直搜索引擎页面处理分析的需求,因此先研究一 下htmlparser的使用,有空再研究nekohtmlmozilla html parser的使用。 

    html的功能还是官方说得最为清楚, 

引用

    HTML Parser is a Java library used to parse HTML in either a linear or nested fashion. Primarily used for transformation or extraction, it features filters, visitors, custom tags and easy to use JavaBeans. It is a fast, robust and well tested package. 

    The two fundamental use-cases that are handled by the parser are extraction and transformation (the syntheses use-case, where HTML pages are created from scratch, is better handled by other tools closer to the source of data). While prior versions concentrated on data extraction from web pages, Version 1.4 of the HTMLParser has substantial improvements in the area of transforming web pages, with simplified tag creation and editing, and verbatim toHtml() method output.



    研究的重点还是extraction的使用,有空再研究transformation的使用。 
1、htmlparser对html页面处理的数据结构 



如图所示,HtmlParser采用了经典的Composite模式,通过RemarkNodeTextNodeTagNodeAbstractNodeTag来描述HTML页面各元素。 

    * org.htmlparser.Node 

    Node接口定义了进行树形结构节点操作的各种典型操作方法,

包括: 

    节点到html文本、text文本的方法:toPlainTextStringtoHtml 

   典型树形结构遍历的方法:getParentgetChildrengetFirstChildgetLastChildgetPreviousSiblinggetNextSiblinggetText 

    获取节点对应的树形结构结构的*节点Page对象方法:getPage 

    获取节点起始位置的方法:getStartPositiongetEndPosition 

   Visitor方法遍历节点时候方法:accept (NodeVisitor visitor) 

    Filter方法:collectInto (NodeList list, NodeFilter filter) 

    Object方法:toStringclone 

    * org.htmlparser.nodes.AbstractNode: 

    AbstractNode是形成HTML树形结构抽象基类,实现了Node接口。 

    htmlparser中,Node分成三类: 

    RemarkNode:代表Html中的注释 

    TagNode:标签节点。 

    TextNode:文本节点 

    这三类节点都继承AbstractNode。 

    * org.htmlparser.nodes.TagNode 

    TagNode包含了对HTML处理的核心的各个类,是所有TAG的基类,其中有分为包含其他TAG的复合节点ComositeTag和不包含其他TAG的叶子节点Tag。 

    复合节点CompositeTag   

        AppletTag,BodyTag,Bullet,BulletList,DefinitionList,DefinitionListBullet,Div,FormTag,FrameSetTag,HeadingTag, 

        HeadTag,Html,LabelTag,LinkTag,ObjectTag,ParagraphTag,ScriptTag,SelectTag,Span,StyleTag,TableColumn, 

       TableHeader,TableRow,TableTag,TextareaTag,TitleTag 

    叶子节点TAG: 

        BaseHrefTag,DoctypeTag,FrameTag,ImageTag,InputTag,JspTag,MetaTag,ProcessingInstructionTag, 
2htmlparserhtml页面处理的算法 

主要是如下几种方式 

l 采用Visitor方式访问Html 

1. 3、htmlparser关键包结构说明  

2.   

3.     htmlparser其实核心代码并不多,好好研究一下其代码,弥补文档不足的问题。同时htmlparser的代码注释和单元测试用例还是很齐全的,也有助于了解htmlparser的用法。  

4.   

5.   

6. 3.1、org.htmlparser  

7.   

8.     定义了htmlparser的一些基础类。其中最为重要的是Parser类。  

9.   

10.     Parser 是htmlparser的最核心的类,其构造函数提供了如下:Parser.createParser (String html,  String charset)、 Parser ()、Parser (Lexer lexer, ParserFeedback fb)、 Parser (URLConnection connection, ParserFeedback fb)、Parser  (String resource, ParserFeedback feedback)、 Parser (String resource)  

11.   

12.   各构造函数的具体用法及含义可以查看其代码,很容易理解。  

13.   

14.   Parser常用的几个方法:  

15.   

16.     *   elements获取元素  

17.   

18.     Parser parser = new Parser (”http://www.google.com”);  

19.     for (NodeIterator i = parser.elements (); i.hasMoreElements (); )  

20.       processMyNodes (i.nextNode ());  

21.   

22.     * parse (NodeFilter filter):通过NodeFilter方式获取  

23.     * visitAllNodesWith (NodeVisitor visitor):通过Nodevisitor方式  

24.     * extractAllNodesThatMatch (NodeFilter filter):通过NodeFilter方式  

25.   

26. 3.2、org.htmlparser.beans  

27.   

28.     对Visitor和Filter的方法进行了封装,定义了针对一些常用html元素操作的bean,简化对常用元素的提取操作。  

29.   

30.     包括:FilterBean、HTMLLinkBean、HTMLTextBean、LinkBean、StringBean、BeanyBaby等。  

31. 3.3、org.htmlparser.nodes  

32.   

33.     定义了基础的node,包括:AbstractNode、RemarkNode、TagNode、TextNode等。  

34. 3.4、org.htmlparser.tags  

35.   

36.     定义了htmlparser的各种tag。  

37. 3.5、org.htmlparser.filters  

38.   

39.      定义了htmlparser所提供的各种filter,主要通过extractAllNodesThatMatch  (NodeFilter filter)来对html页面指定类型的元素进行过滤,包括:AndFilter、 CssSelectorNodeFilter、 HasAttributeFilter、HasChildFilter、 HasParentFilter、HasSiblingFilter、 IsEqualFilter、LinkRegexFilter、 LinkStringFilter、NodeClassFilter、 NotFilter、OrFilter、RegexFilter、 StringFilter、TagNameFilter、XorFilter  

40. 3.6、org.htmlparser.visitors  

41.   

42.     定义了htmlparser所提供的各种visitor,主要通过visitAllNodesWith (NodeVisitor visitor)来对 html页面元素进行遍历,包括:HtmlPage、LinkFindingVisitor、NodeVisitor、  ObjectFindingVisitor、StringFindingVisitor、TagFindingVisitor、  TextExtractingVisitor、UrlModifyingVisitor  

43.   

44.    

45. 3.7、org.htmlparser.parserapplications  

46.   

47.    定义了一些实用的工具,包括LinkExtractor、SiteCapturer、StringExtractor、WikiCapturer,这几个类也可以作为htmlparser使用样例。  

48. 3.8、org.htmlparser.tests  

49.   

50.    对各种功能的单元测试用例,也可以作为htmlparser使用的样例。  

51.   

52.    

53. 4、htmlparser的使用样例  

54.   

55.    

56.   

57. import java.net.URL;  

58.   

59. import junit.framework.TestCase;  

60.   

61. import org.apache.log4j.Logger;  

62. import org.htmlparser.Node;  

63. import org.htmlparser.NodeFilter;  

64. import org.htmlparser.Parser;  

65. import org.htmlparser.Tag;  

66. import org.htmlparser.beans.LinkBean;  

67. import org.htmlparser.filters.NodeClassFilter;  

68. import org.htmlparser.filters.OrFilter;  

69. import org.htmlparser.filters.TagNameFilter;  

70. import org.htmlparser.tags.HeadTag;  

71. import org.htmlparser.tags.ImageTag;  

72. import org.htmlparser.tags.InputTag;  

73. import org.htmlparser.tags.LinkTag;  

74. import org.htmlparser.tags.OptionTag;  

75. import org.htmlparser.tags.SelectTag;  

76. import org.htmlparser.tags.TableColumn;  

77. import org.htmlparser.tags.TableRow;  

78. import org.htmlparser.tags.TableTag;  

79. import org.htmlparser.tags.TitleTag;  

80. import org.htmlparser.util.NodeIterator;  

81. import org.htmlparser.util.NodeList;  

82. import org.htmlparser.util.ParserException;  

83. import org.htmlparser.visitors.HtmlPage;  

84. import org.htmlparser.visitors.NodeVisitor;  

85. import org.htmlparser.visitors.ObjectFindingVisitor;  

86.   

87. public class ParserTestCase extends TestCase {  

88.   

89.     private static final Logger logger = Logger.getLogger(ParserTestCase.class);  

90.   

91.     public ParserTestCase(String name) {  

92.         super(name);  

93.     }  

94.     /* 

95.      * 测试ObjectFindVisitor的用法 

96.      */  

97.     public void testImageVisitor() {  

98.         try {  

99.             ImageTag imgLink;  

100.             ObjectFindingVisitor visitor = new ObjectFindingVisitor(  

101.                     ImageTag.class);  

102.             Parser parser = new Parser();  

103.             parser.setURL(”http://www.google.com”);  

104.             parser.setEncoding(parser.getEncoding());  

105.             parser.visitAllNodesWith(visitor);  

106.             Node[] nodes = visitor.getTags();  

107.             for (int i = 0; i < nodes.length; i++) {  

108.                 imgLink = (ImageTag) nodes[i];  

109.                 logger.fatal(”testImageVisitor() ImageURL = “  

110.                         + imgLink.getImageURL());  

111.                 logger.fatal(”testImageVisitor() ImageLocation = “  

112.                         + imgLink.extractImageLocn());  

113.                 logger.fatal(”testImageVisitor() SRC = “  

114.                         + imgLink.getAttribute(”SRC”));  

115.             }  

116.         }  

117.         catch (Exception e) {  

118.             e.printStackTrace();  

119.         }  

120.     }  

121.     /* 

122.      * 测试TagNameFilter用法 

123.      */  

124.     public void testNodeFilter() {  

125.         try {  

126.             NodeFilter filter = new TagNameFilter(”IMG”);  

127.             Parser parser = new Parser();  

128.             parser.setURL(”http://www.google.com”);  

129.             parser.setEncoding(parser.getEncoding());  

130.             NodeList list = parser.extractAllNodesThatMatch(filter);  

131.             for (int i = 0; i < list.size(); i++) {  

132.                 logger.fatal(”testNodeFilter() ” + list.elementAt(i).toHtml());  

133.             }  

134.         } catch (Exception e) {  

135.             e.printStackTrace();  

136.         }  

137.   

138.     }  

139.     /* 

140.      * 测试NodeClassFilter用法 

141.      */  

142.     public void testLinkTag() {  

143.         try {  

144.   

145.             NodeFilter filter = new NodeClassFilter(LinkTag.class);  

146.             Parser parser = new Parser();  

147.             parser.setURL(”http://www.google.com”);  

148.             parser.setEncoding(parser.getEncoding());  

149.             NodeList list = parser.extractAllNodesThatMatch(filter);  

150.             for (int i = 0; i < list.size(); i++) {  

151.                 LinkTag node = (LinkTag) list.elementAt(i);  

152.                 logger.fatal(”testLinkTag() Link is :” + node.extractLink());  

153.             }  

154.         } catch (Exception e) {  

155.             e.printStackTrace();  

156.         }  

157.   

158.     }  

159.     /* 

160.      * 测试<link href=” text=’text/css’ rel=’stylesheet’ />用法 

161.      */  

162.     public void testLinkCSS() {  

163.         try {  

164.   

165.             Parser parser = new Parser();  

166.             parser  

167.                     .setInputHTML(”<head><title>Link Test</title>”  

168.                             + “<link href=’/test01/css.css’ text=’text/css’ rel=’stylesheet’ />”  

169.                             + “<link href=’/test02/css.css’ text=’text/css’ rel=’stylesheet’ />”  

170.                             + “</head>” + “<body>”);  

171.             parser.setEncoding(parser.getEncoding());  

172.             NodeList nodeList = null;  

173.   

174.             for (NodeIterator e = parser.elements(); e.hasMoreNodes();) {  

175.                 Node node = e.nextNode();  

176.                 logger  

177.                         .fatal(”testLinkCSS()” + node.getText()  

178.                                 + node.getClass());  

179.   

180.             }  

181.         } catch (Exception e) {  

182.             e.printStackTrace();  

183.         }  

184.     }  

185.     /* 

186.      * 测试OrFilter的用法 

187.      */  

188.     public void testOrFilter() {  

189.         NodeFilter inputFilter = new NodeClassFilter(InputTag.class);  

190.         NodeFilter selectFilter = new NodeClassFilter(SelectTag.class);  

191.         Parser myParser;  

192.         NodeList nodeList = null;  

193.   

194.         try {  

195.             Parser parser = new Parser();  

196.             parser  

197.                     .setInputHTML(”<head><title>OrFilter Test</title>”  

198.                             + “<link href=’/test01/css.css’ text=’text/css’ rel=’stylesheet’ />”  

199.                             + “<link href=’/test02/css.css’ text=’text/css’ rel=’stylesheet’ />”  

200.                             + “</head>”  

201.                             + “<body>”  

202.                             + “<input type=’text’ value=’text1′ name=’text1′/>”  

203.                             + “<input type=’text’ value=’text2′ name=’text2′/>”  

204.                             + “<select><option id=’1′>1</option><option id=’2′>2</option><option id=’3′></option></select>”  

205.                             + “<a href=’http://www.yeeach.com’>yeeach.com</a>”  

206.                             + “</body>”);  

207.   

208.             parser.setEncoding(parser.getEncoding());  

209.             OrFilter lastFilter = new OrFilter();  

210.             lastFilter.setPredicates(new NodeFilter[] { selectFilter,  

211.                     inputFilter });  

212.             nodeList = parser.parse(lastFilter);  

213.             for (int i = 0; i <= nodeList.size(); i++) {  

214.                 if (nodeList.elementAt(i) instanceof InputTag) {  

215.                     InputTag tag = (InputTag) nodeList.elementAt(i);  

216.                     logger.fatal(”OrFilter tag name is :” + tag.getTagName()  

217.                             + ” ,tag value is:” + tag.getAttribute(”value”));  

218.                 }  

219.                 if (nodeList.elementAt(i) instanceof SelectTag) {  

220.                     SelectTag tag = (SelectTag) nodeList.elementAt(i);  

221.                     NodeList list = tag.getChildren();  

222.   

223.                     for (int j = 0; j < list.size(); j++) {  

224.                         OptionTag option = (OptionTag) list.elementAt(j);  

225.                         logger  

226.                                 .fatal(”OrFilter Option”  

227.                                         + option.getOptionText());  

228.                     }  

229.   

230.                 }  

231.             }  

232.   

233.         } catch (ParserException e) {  

234.             e.printStackTrace();  

235.         }  

236.     }  

237.     /* 

238.      * 测试对<table><tr><td></td></tr></table>的解析 

239.      */  

240.     public void testTable() {  

241.         Parser myParser;  

242.         NodeList nodeList = null;  

243.         myParser = Parser.createParser(”<body> ” + “<table id=’table1′ >”  

244.                 + “<tr><td>1-11</td><td>1-12</td><td>1-13</td>”  

245.                 + “<tr><td>1-21</td><td>1-22</td><td>1-23</td>”  

246.                 + “<tr><td>1-31</td><td>1-32</td><td>1-33</td></table>”  

247.                 + “<table id=’table2′ >”  

248.                 + “<tr><td>2-11</td><td>2-12</td><td>2-13</td>”  

249.                 + “<tr><td>2-21</td><td>2-22</td><td>2-23</td>”  

250.                 + “<tr><td>2-31</td><td>2-32</td><td>2-33</td></table>”  

251.                 + “</body>”, “GBK”);  

252.         NodeFilter tableFilter = new NodeClassFilter(TableTag.class);  

253.         OrFilter lastFilter = new OrFilter();  

254.         lastFilter.setPredicates(new NodeFilter[] { tableFilter });  

255.         try {  

256.             nodeList = myParser.parse(lastFilter);  

257.             for (int i = 0; i <= nodeList.size(); i++) {  

258.                 if (nodeList.elementAt(i) instanceof TableTag) {  

259.                     TableTag tag = (TableTag) nodeList.elementAt(i);  

260.                     TableRow[] rows = tag.getRows();  

261.   

262.                     for (int j = 0; j < rows.length; j++) {  

263.                         TableRow tr = (TableRow) rows[j];  

264.                         TableColumn[] td = tr.getColumns();  

265.                         for (int k = 0; k < td.length; k++) {  

266.                             logger.fatal(”<td>” + td[k].toPlainTextString());  

267.                         }  

268.   

269.                     }  

270.   

271.                 }  

272.             }  

273.   

274.         } catch (ParserException e) {  

275.             e.printStackTrace();  

276.         }  

277.     }  

278.     /* 

279.      * 测试NodeVisitor的用法,遍历所有节点 

280.      */  

281.     public void testVisitorAll() {  

282.         try {  

283.             Parser parser = new Parser();  

284.             parser.setURL(”http://www.google.com”);  

285.             parser.setEncoding(parser.getEncoding());  

286.             NodeVisitor visitor = new NodeVisitor() {  

287.                 public void visitTag(Tag tag) {  

288.                     logger.fatal(”testVisitorAll()  Tag name is :”  

289.                             + tag.getTagName() + ” \n Class is :”  

290.                             + tag.getClass());  

291.                 }  

292.   

293.             };  

294.   

295.             parser.visitAllNodesWith(visitor);  

296.         } catch (ParserException e) {  

297.             e.printStackTrace();  

298.         }  

299.     }  

300.     /* 

301.      * 测试对指定Tag的NodeVisitor的用法 

302.      */  

303.     public void testTagVisitor() {  

304.         try {  

305.   

306.             Parser parser = new Parser(  

307.                     “<head><title>dddd</title>”  

308.                             + “<link href=’/test01/css.css’ text=’text/css’ rel=’stylesheet’ />”  

309.                             + “<link href=’/test02/css.css’ text=’text/css’ rel=’stylesheet’ />”  

310.                             + “</head>” + “<body>”  

311.                             + “<a href=’http://www.yeeach.com’>yeeach.com</a>”  

312.                             + “</body>”);  

313.             NodeVisitor visitor = new NodeVisitor() {  

314.                 public void visitTag(Tag tag) {  

315.                     if (tag instanceof HeadTag) {  

316.                         logger.fatal(”visitTag() HeadTag : Tag name is :”  

317.                                 + tag.getTagName() + ” \n Class is :”  

318.                                 + tag.getClass() + “\n Text is :”  

319.                                 + tag.getText());  

320.                     } else if (tag instanceof TitleTag) {  

321.                         logger.fatal(”visitTag() TitleTag : Tag name is :”  

322.                                 + tag.getTagName() + ” \n Class is :”  

323.                                 + tag.getClass() + “\n Text is :”  

324.                                 + tag.getText());  

325.   

326.   

327.                     } else if (tag instanceof LinkTag) {  

328.                         logger.fatal(”visitTag() LinkTag : Tag name is :”  

329.                                 + tag.getTagName() + ” \n Class is :”  

330.                                 + tag.getClass() + “\n Text is :”  

331.                                 + tag.getText() + ” \n getAttribute is :”  

332.                                 + tag.getAttribute(”href”));  

333.                     } else {  

334.                         logger.fatal(”visitTag() : Tag name is :”  

335.                                 + tag.getTagName() + ” \n Class is :”  

336.                                 + tag.getClass() + “\n Text is :”  

337.                                 + tag.getText());  

338.                     }  

339.   

340.                 }  

341.   

342.             };  

343.   

344.             parser.visitAllNodesWith(visitor);  

345.         } catch (Exception e) {  

346.             e.printStackTrace();  

347.         }  

348.     }  

349.     /* 

350.      * 测试HtmlPage的用法 

351.      */  

352.     public void testHtmlPage() {  

353.         String inputHTML = “<html>” + “<head>”  

354.                 + “<title>Welcome to the HTMLParser website</title>”  

355.                 + “</head>” + “<body>” + “Welcome to HTMLParser”  

356.                 + “<table id=’table1′ >”  

357.                 + “<tr><td>1-11</td><td>1-12</td><td>1-13</td>”  

358.                 + “<tr><td>1-21</td><td>1-22</td><td>1-23</td>”  

359.                 + “<tr><td>1-31</td><td>1-32</td><td>1-33</td></table>”  

360.                 + “<table id=’table2′ >”  

361.                 + “<tr><td>2-11</td><td>2-12</td><td>2-13</td>”  

362.                 + “<tr><td>2-21</td><td>2-22</td><td>2-23</td>”  

363.                 + “<tr><td>2-31</td><td>2-32</td><td>2-33</td></table>”  

364.                 + “</body>” + “</html>”;  

365.         Parser parser = new Parser();  

366.         try {  

367.             parser.setInputHTML(inputHTML);  

368.             parser.setEncoding(parser.getURL());  

369.             HtmlPage page = new HtmlPage(parser);  

370.             parser.visitAllNodesWith(page);  

371.             logger.fatal(”testHtmlPage -title is :” + page.getTitle());  

372.             NodeList list = page.getBody();  

373.   

374.             for (NodeIterator iterator = list.elements(); iterator  

375.                     .hasMoreNodes();) {  

376.                 Node node = iterator.nextNode();  

377.                 logger.fatal(”testHtmlPage -node  is :” + node.toHtml());  

378.             }  

379.   

380.         } catch (ParserException e) {  

381.             // TODO Auto-generated catch block  

382.             e.printStackTrace();  

383.         }  

384.     }  

385.     /* 

386.      * 测试LinkBean的用法 

387.      */  

388.     public void testLinkBean() {  

389.         Parser parser = new Parser();  

390.   

391.         LinkBean linkBean = new LinkBean();  

392.         linkBean.setURL(”http://www.google.com”);  

393.         URL[] urls = linkBean.getLinks();  

394.   

395.         for (int i = 0; i < urls.length; i++) {  

396.             URL url = urls[i];  

397.             logger.fatal(”testLinkBean() -url  is :” + url);  

398.         }  

399.   

400.     }  

401.   

402. }  

package cn;


import java.io.BufferedReader;

import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.io.OutputStream;

import java.net.ConnectException;

import java.net.MalformedURLException;

import java.net.URL;

import java.util.ArrayList;

import java.util.List;

import java.util.UUID;


import org.htmlparser.NodeFilter;

import org.htmlparser.Parser;

import org.htmlparser.filters.TagNameFilter;

import org.htmlparser.tags.ImageTag;

import org.htmlparser.util.NodeList;

import org.htmlparser.util.ParserException;

import org.htmlparser.visitors.HtmlPage;


public class getAll {

private final static String CRLF = System.getProperty("line.separator");// 回车换行


public static void makeHtm(int x) {

InputStream instr = null;

List list = new ArrayList<String>();

for (; x > 89205; x--) {

list.clear();

try {

URL ur = new URL("你要扒的地址" + x + ".html"); // 这个要按照情况而定了,我不多说了。

try {

System.out.println("正在加载页面:     " + ur.toString());

instr = ur.openStream(); // 获得网页输出流

} catch (ConnectException e) {

System.out.println(e.toString());

makeHtm(--x); // 如果连接超时,将会抛出这个异常并且换成新的网址继续扒。

}

String s = null;

BufferedReader in = new BufferedReader(new InputStreamReader(

instr));

StringBuffer sb = new StringBuffer();


while ((s = in.readLine()) != null) {

sb.append(s + CRLF); // 读取网页信息,放入字符串缓冲区

}

Parser parser = Parser.createParser(sb.toString(), "utf-8"); // 获得整个网页的缓冲区创建解析器

HtmlPage page = new HtmlPage(parser); // 把解析器交给解析htmlpage

try {

parser.visitAllNodesWith(page);

} catch (ParserException e1) {

e1 = null;

}

NodeList nodelist = page.getBody(); // 获得网页的body部分

NodeFilter filter = new TagNameFilter("IMG"); // 过滤 img标签也可以过滤

// sapna等标签


nodelist = nodelist.extractAllNodesThatMatch(filter, true);

for (int i = 0; i < nodelist.size(); i++) {

ImageTag link = (ImageTag) nodelist.elementAt(i); // 获得所有的

// IMG标签

String src = link.getAttribute("src"); // 获得img标签的src属性、这个属性就是

// 就是那个图片的网址

list.add(src);

/**

 * LinkTag link = (LinkTag) nodelist.elementAt(i); // 链接地址

 * System.out.println(link.getAttribute("href") + "\n"); //

 * 链接名称 System.out.println(link.getStringText());

 * 如果过滤超链接就这样写 当然上面的 filter的过滤条件要改成"A"

 */

}

in.close();

down(list, x); // 调用down方法交给 那个存放链接的集合,和 当前下载的x

list.clear();

} catch (MalformedURLException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

}

System.out.println("下载完成");

}


public static void down(List<String> list, int x) throws IOException {

String substring = UUID.randomUUID().toString();

InputStream in = null;

try {

if (list != null) {

for (String src : list) {

URL url = new URL(src);

try {

System.out.println("正在下载:   " + url.toString());

in = url.openStream();

} catch (ConnectException e) {

System.out.println(e.toString());

list.clear();

makeHtm(--x);

}

String string = UUID.randomUUID().toString();

File forder = new File("F://fuck//" + substring);

if (!forder.exists()) {

forder.mkdir();

}

File file = new File("F://xx//" + substring + "//" + string

+ ".jpg"); // 每个网页的图片都放在一个UUID的文件夹里,每个图片都是

// 一个UUID的名字

OutputStream out = new FileOutputStream(file);

byte[] b = new byte[1024 * 6]; // 我习惯这个数字 你可以改大点

int len;

while ((len = in.read(b)) != -1) {

out.write(b, 0, len); // 流的对拷,不多说了

out.flush();

}

}

}

} catch (MalformedURLException e) {

makeHtm(--x);

e.printStackTrace();

}

}

}

                        当然 你别忘记  写个 main方法调用他 

共同学习,共同进步。

我的博客   http://avjv.blog.163.com/   邮箱 gaovvh@sina.cn