packageparser;
importjava.io.BufferedReader;
importjava.io.BufferedWriter;
importjava.io.FileWriter;
importjava.io.IOException;
importjava.io.InputStream;
importjava.io.InputStreamReader;
importjava.net.MalformedURLException;
importjava.net.URL;
/**
*基本能实现网页抓取,不过要手动输入URL将整个html内容保存到指定文件
*
*@authorchenguoyong
*
*/
publicclassScrubSelectedWeb{
privatefinalstaticStringCRLF=System.getProperty("line.separator");
/**
*@paramargs
*/
publicstaticvoidmain(String[]args){
try{
URLur=newURL("http://10.249.187.199:8083/injs100/");
InputStreaminstr=ur.openStream();
Strings,str;
BufferedReaderin=newBufferedReader(newInputStreamReader(instr));
StringBuffersb=newStringBuffer();
BufferedWriterout=newBufferedWriter(newFileWriter(
"D:/outPut.txt"));
while((s=in.readLine())!=null){
sb.append(s+CRLF);
}
System.out.println(sb);
str=newString(sb);
out.write(str);
out.close();
in.close();
}catch(MalformedURLExceptione){
e.printStackTrace();
}catch(IOExceptione){
e.printStackTrace();
}
}
}
基本能实现网页抓取,不过要手动输入URL,此外没有重构。只是一个简单的思路。
htmlparser是一个纯的java写的html解析的库,htmlparser不依赖于其它的java库,htmlparser主要用于改造或提取html。htmlparser能超高速解析html,而且不会出错。毫不夸张地说,htmlparser就是目前最好的html解析和分析的工具。无论你是想抓取网页数据还是改造html的内容,用了htmlparser绝对会忍不住称赞。由于htmlparser结构设计精良,所以扩展htmlparser非常便利。
Htmlparser中文论坛.http://bbs.hexiao.cn/thread.php?fid=6
ConstructorSummary |
Parser()
Parser(URLConnectionconnection)
ConstructaparserusingtheprovidedURLConnection.
Method:
staticParsercreateParser(Stringhtml,Stringcharset)
Createstheparseronaninputstring.
voidvisitAllNodesWith(NodeVisitorvisitor)
Applythegivenvisitortothecurrentpage.
getBody() |
|
TableTag[] |
|
getTitle() |
|
void |
|
void |
ConstructorSummary |
NodeList() |
NodeListextractAllNodesThatMatch(NodeFilterfilter)
Filterthelistwiththegivenfilternon-recursively.
NodeListextractAllNodesThatMatch(NodeFilterfilter,booleanrecursive)
Filterthelistwiththegivenfilter.
packageparser;
importorg.htmlparser.Parser;
importorg.htmlparser.Node;
importorg.htmlparser.NodeFilter;
importorg.htmlparser.Parser;
importorg.htmlparser.filters.TagNameFilter;
importorg.htmlparser.tags.LinkTag;
importorg.htmlparser.tags.TableTag;
importorg.htmlparser.util.NodeList;
importorg.htmlparser.util.ParserException;
importorg.htmlparser.visitors.HtmlPage;
/**
*htmlparser取得一段html代码里面所有的链接地址和链接名称
*
*@authorchenguoyong
*
*/
publicclassTesthtmlparser{
/**
*@paramargs
*/
publicstaticvoidmain(String[]args){
Stringhtmlcode="<HTML><HEAD><TITLE>AAA</TITLE></HEAD><BODY>"
+"<ahref='http://topic.csdn.net/u/20080522/14/0ff402ef-c382-499a-8213-ba6b2f550425.html'>连接1</a>"
+"<ahref='http://topic.csdn.net'>连接2</a></BODY></HTML>";
//创建Parser对象根据传给字符串和指定的编码
Parserparser=Parser.createParser(htmlcode,"GBK");
//创建HtmlPage对象HtmlPage(Parserparser)
HtmlPagepage=newHtmlPage(parser);
try{
//HtmlPageextendsvisitor,Applythegivenvisitortothecurrent
//page.
parser.visitAllNodesWith(page);
}catch(ParserExceptione1){
e1=null;
}
//所有的节点
NodeListnodelist=page.getBody();
//建立一个节点filter用于过滤节点
NodeFilterfilter=newTagNameFilter("A");
//得到所有过滤后,想要的节点
nodelist=nodelist.extractAllNodesThatMatch(filter,true);
for(inti=0;i<nodelist.size();i++){
LinkTaglink=(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
packageparser;
importorg.htmlparser.Parser;
importorg.htmlparser.beans.StringBean;
importorg.htmlparser.filters.NodeClassFilter;
importorg.htmlparser.parserapplications.StringExtractor;
importorg.htmlparser.tags.BodyTag;
importorg.htmlparser.util.NodeList;
importorg.htmlparser.util.ParserException;
/**
*使用HtmlParser抓去网页内容:要抓去页面的内容最方便的方法就是使用StringBean.里面有几个控制页面内容的几个参数.
*在后面的代码中会有说明.Htmlparser包中还有一个示例StringExtractor里面有个直接得到内容的方法,
*其中也是使用了StringBean.另外直接解析Parser的每个标签也可以的.
*
*@authorchenguoyong
*
*/
publicclassGetContent{
publicvoidgetContentUsingStringBean(Stringurl){
StringBeansb=newStringBean();
sb.setLinks(true);//是否显示web页面的连接(Links)
//为了取得页面的整洁美观一般设置上面两项为true,如果要保持页面的原有格式,如代码页面的空格缩进可以设置为false
sb.setCollapse(true);//如果是true的话把一系列空白字符用一个字符替代.
sb.setReplaceNonBreakingSpaces(true);//Iftrueregularspace
sb
.setURL("http://www.blogjava.net/51AOP/archive/2006/07/19/59064.html");
System.out.println("TheContentis:\n"+sb.getStrings());
}
publicvoidgetContentUsingStringExtractor(Stringurl,booleanlink){
//StringExtractor内部机制和上面的一样.做了一下包装
StringExtractorse=newStringExtractor(url);
Stringtext=null;
try{
text=se.extractStrings(link);
System.out.println("Thecontentis:\n"+text);
}catch(ParserExceptione){
e.printStackTrace();
}
}
publicvoidgetContentUsingParser(Stringurl){
NodeListnl;
try{
Parserp=newParser(url);
nl=p.parse(newNodeClassFilter(BodyTag.class));
BodyTagbt=(BodyTag)nl.elementAt(0);
System.out.println(bt.toPlainTextString());//保留原来的内容格式.包含js代码
}catch(ParserExceptione){
e.printStackTrace();
}
}
/**
*@paramargs
*/
publicstaticvoidmain(String[]args){
Stringurl="http://www.blogjava.net/51AOP/archive/2006/07/19/59064.html";
//newGetContent().getContentUsingParser(url);
//--------------------------------------------------
newGetContent().getContentUsingStringBean(url);
}
}
packageparser;
importjava.io.BufferedReader;
importjava.io.BufferedWriter;
importjava.io.FileWriter;
importjava.io.IOException;
importjava.io.InputStream;
importjava.io.InputStreamReader;
importjava.net.MalformedURLException;
importjava.net.URL;
/**
*基本能实现网页抓取,不过要手动输入URL将整个html内容保存到指定文件
*
*@authorchenguoyong
*
*/
publicclassScrubSelectedWeb{
privatefinalstaticStringCRLF=System.getProperty("line.separator");
/**
*@paramargs
*/
publicstaticvoidmain(String[]args){
try{
URLur=newURL("http://www.google.cn/");
InputStreaminstr=ur.openStream();
Strings,str;
BufferedReaderin=newBufferedReader(newInputStreamReader(instr));
StringBuffersb=newStringBuffer();
BufferedWriterout=newBufferedWriter(newFileWriter(
"D:/outPut.txt"));
while((s=in.readLine())!=null){
sb.append(s+CRLF);
}
System.out.println(sb);
str=newString(sb);
out.write(str);
out.close();
in.close();
}catch(MalformedURLExceptione){
e.printStackTrace();
}catch(IOExceptione){
e.printStackTrace();
}
}
}
packageparser;
importorg.htmlparser.Node;
importorg.htmlparser.NodeFilter;
importorg.htmlparser.Parser;
importorg.htmlparser.filters.TagNameFilter;
importorg.htmlparser.tags.TableTag;
importorg.htmlparser.util.NodeList;
/**
*标题:利用htmlparser提取网页纯文本的例子
*/
publicclassTestHTMLParser2{
/**
*读取目标html内容
*
*/
publicstaticvoidtestHtml(){
try{
StringsCurrentLine;
StringsTotalString;
sCurrentLine="";
sTotalString="";
java.io.InputStreaml_urlStream;
java.net.URLl_url=newjava.net.URL(
"http://10.249.187.199:8083/injs100/");
java.net.HttpURLConnectionl_connection=(java.net.HttpURLConnection)l_url
.openConnection();
l_connection.connect();
l_urlStream=l_connection.getInputStream();
java.io.BufferedReaderl_reader=newjava.io.BufferedReader(
newjava.io.InputStreamReader(l_urlStream));
while((sCurrentLine=l_reader.readLine())!=null){
sTotalString+=sCurrentLine+"\r\n";
}
StringtestText=extractText(sTotalString);
}catch(Exceptione){
e.printStackTrace();
}
}
/**
*抽取纯文本信息
*@paraminputHtml:html文本
*@return
*@throwsException
*/
publicstaticStringextractText(StringinputHtml)throwsException{
StringBuffertext=newStringBuffer();
Parserparser=Parser.createParser(newString(inputHtml.getBytes(),
"GBK"),"GBK");
//遍历所有的节点
NodeListnodes=parser.extractAllNodesThatMatch(newNodeFilter(){
publicbooleanaccept(Nodenode){
returntrue;
}
});
System.out.println(nodes.size());
for(inti=0;i<nodes.size();i++){
Nodenodet=nodes.elementAt(i);
//字符串的代表性节点:节点的描述
text.append(newString(nodet.toPlainTextString().getBytes("GBK"))
+"\r\n");
}
returntext.toString();
}
/**
*读取文件的方式/utl来分析内容.filePath也可以是一个Url.
*@paramresource:文件/Url
*@throwsException
*/
publicstaticvoidtest5(Stringresource)throwsException{
ParsermyParser=newParser(resource);
myParser.setEncoding("GBK");
StringfilterStr="table";
NodeFilterfilter=newTagNameFilter(filterStr);
NodeListnodeList=myParser.extractAllNodesThatMatch(filter);
/*for(inti=0;i<nodeList.size();i++)
{
TableTagtabletag=(TableTag)nodeList.elementAt(i);
//标签名称
System.out.println(tabletag.getTagName());
System.out.println(tabletag.getText());
}*/
TableTagtabletag=(TableTag)nodeList.elementAt(1);
}
publicstaticvoidmain(String[]args)throwsException{
test5("http://10.249.187.199:8083/injs100/");
//testHtml();
}
}
packageparser;
importorg.apache.log4j.Logger;
importorg.htmlparser.NodeFilter;
importorg.htmlparser.Parser;
importorg.htmlparser.filters.NodeClassFilter;
importorg.htmlparser.filters.OrFilter;
importorg.htmlparser.filters.TagNameFilter;
importorg.htmlparser.tags.TableColumn;
importorg.htmlparser.tags.TableRow;
importorg.htmlparser.tags.TableTag;
importorg.htmlparser.util.NodeList;
importorg.htmlparser.util.ParserException;
importjunit.framework.TestCase;
publicclassParserTestCaseextendsTestCase{
privatestaticfinalLoggerlogger=Logger.getLogger(ParserTestCase.class);
publicParserTestCase(Stringname){
super(name);
}
/**
*测试对<table>
*<tr>
*<td></td>
*</tr>
*</table>的解析
*/
publicvoidtestTable(){
ParsermyParser;
NodeListnodeList=null;
myParser=Parser
.createParser(
"<body>"
+"<tableid=’table1′>"
+"<trid='tro1'><td>1-11</td><td>1-12</td><td>1-13</td></tr>"
+"<trid='tro2'><td>1-21</td><td>1-22</td><td>1-23</td></tr>"
+"<trid='tro3'><td>1-31</td><td>1-32</td><td>1-33</td></tr></table>"
+"<tableid=’table2′>"
+"<trid='tro4'><td>2-11</td><td>2-12</td><td>2-13</td></tr>"
+"<trid='tro5'><td>2-21</td><td>2-22</td><td>2-23</td></tr>"
+"<trid='tro6'><td>2-31</td><td>2-32</td><td>2-33</td></tr></table>"
+"</body>","GBK");
NodeFiltertableFilter=newNodeClassFilter(TableTag.class);
OrFilterlastFilter=newOrFilter();
lastFilter.setPredicates(newNodeFilter[]{tableFilter});
try{
nodeList=myParser.parse(lastFilter);
for(inti=0;i<=nodeList.size();i++){
if(nodeList.elementAt(i)instanceofTableTag){
TableTagtag=(TableTag)nodeList.elementAt(i);
TableRow[]rows=tag.getRows();
for(intj=0;j<rows.length;j++){
TableRowtr=(TableRow)rows[j];
System.out.println(tr.getAttribute("id"));
if(tr.getAttribute("id").equalsIgnoreCase("tro1")){
TableColumn[]td=tr.getColumns();
for(intk=0;k<td.length;k++){
//logger.fatal("<td>"+
//td[k].toPlainTextString());
System.out.println("<td>"
+td[k].toPlainTextString());
}
}
}
}
}
}catch(ParserExceptione){
e.printStackTrace();
}
}
/**
*得到目标数据
*
*@paramurl:目标url
*@throwsException
*/
publicstaticvoidgetDatabyUrl(Stringurl)throwsException{
ParsermyParser=newParser(url);
NodeListnodeList=null;
myParser.setEncoding("gb2312");
NodeFiltertableFilter=newNodeClassFilter(TableTag.class);
OrFilterlastFilter=newOrFilter();
lastFilter.setPredicates(newNodeFilter[]{tableFilter});
try{
nodeList=myParser.parse(lastFilter);
//可以从数据table的size:19-21开始到结束
for(inti=15;i<=nodeList.size();i++){
if(nodeList.elementAt(i)instanceofTableTag){
TableTagtag=(TableTag)nodeList.elementAt(i);
TableRow[]rows=tag.getRows();
for(intj=0;j<rows.length;j++){
TableRowtr=(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(intk=0;k<td.length;k++){
System.out.println("<td>内容:"
+td[k].toPlainTextString().trim());
}
}
}
}
}
}
}catch(ParserExceptione){
e.printStackTrace();
}
}
/**
*测试已经得出有数据时table:22个,没有数据时table:19个
*
*@paramargs
*/
publicstaticvoidmain(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(Exceptione){
e.printStackTrace();
}
}
}
packagecom.jscud.test;
importjava.io.BufferedReader;
importjava.io.File;
importjava.io.FileInputStream;
importjava.io.InputStreamReader;
importorg.htmlparser.Node;
importorg.htmlparser.NodeFilter;
importorg.htmlparser.Parser;
importorg.htmlparser.filters.NodeClassFilter;
importorg.htmlparser.filters.OrFilter;
importorg.htmlparser.nodes.TextNode;
importorg.htmlparser.tags.LinkTag;
importorg.htmlparser.util.NodeList;
importorg.htmlparser.util.ParserException;
importorg.htmlparser.visitors.HtmlPage;
importorg.htmlparser.visitors.TextExtractingVisitor;
importcom.jscud.util.LogMan;//一个日志记录类
/**
*演示了HtmlParse的应用.
*
*@authorscudhttp://www.jscud.com(http://www.jscud.com/)
*/
publicclassParseHtmlTest
{
publicstaticvoidmain(String[]args)throwsException
{
StringaFile="e:/jscud/temp/test.htm";
Stringcontent=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.
*
*@paramresource文件/Url
*/
publicstaticvoidtest5(Stringresource)throwsException
{
ParsermyParser=newParser(resource);
//设置编码
myParser.setEncoding("GBK");
HtmlPagevisitor=newHtmlPage(myParser);
myParser.visitAllNodesWith(visitor);
StringtextInPage=visitor.getTitle();
System.out.println(textInPage);
}
/**
*按页面方式处理.对一个标准的Html页面,推荐使用此种方式.
*/
publicstaticvoidtest4(Stringcontent)throwsException
{
ParsermyParser;
myParser=Parser.createParser(content,"GBK");
HtmlPagevisitor=newHtmlPage(myParser);
myParser.visitAllNodesWith(visitor);
StringtextInPage=visitor.getTitle();
System.out.println(textInPage);
}
/**
*利用Visitor模式解析html页面.
*
*小优点:翻译了<>等符号
*缺点:好多空格,无法提取link
*
*/
publicstaticvoidtest3(Stringcontent)throwsException
{
ParsermyParser;
myParser=Parser.createParser(content,"GBK");
TextExtractingVisitorvisitor=newTextExtractingVisitor();
myParser.visitAllNodesWith(visitor);
StringtextInPage=visitor.getExtractedText();
System.out.println(textInPage);
}
/**
*得到普通文本和链接的内容.
*
*使用了过滤条件.
*/
publicstaticvoidtest2(Stringcontent)throwsParserException
{
ParsermyParser;
NodeListnodeList=null;
myParser=Parser.createParser(content,"GBK");
NodeFiltertextFilter=newNodeClassFilter(TextNode.class);
NodeFilterlinkFilter=newNodeClassFilter(LinkTag.class);
//暂时不处理meta
//NodeFiltermetaFilter=newNodeClassFilter(MetaTag.class);
OrFilterlastFilter=newOrFilter();
lastFilter.setPredicates(newNodeFilter[]{textFilter,linkFilter});
nodeList=myParser.parse(lastFilter);
Node[]nodes=nodeList.toNodeArray();
for(inti=0;i<nodes.length;i++)
{
Nodeanode=(Node)nodes[i];
Stringline="";
if(anodeinstanceofTextNode)
{
TextNodetextnode=(TextNode)anode;
//line=textnode.toPlainTextString().trim();
line=textnode.getText();
}
elseif(anodeinstanceofLinkTag)
{
LinkTaglinknode=(LinkTag)anode;
line=linknode.getLink();
//@todo("")过滤jsp标签:可以自己实现这个函数
//line=StringFunc.replace(line,"<%.*%>","");
}
if(isTrimEmpty(line))
continue;
System.out.println(line);
}
}
/**
*解析普通文本节点.
*
*@paramcontent
*@throwsParserException
*/
publicstaticvoidtest1(Stringcontent)throwsParserException
{
ParsermyParser;
Node[]nodes=null;
myParser=Parser.createParser(content,null);
nodes=myParser.extractAllNodesThatAre(TextNode.class);//exceptioncouldbethrownhere
for(inti=0;i<nodes.length;i++)
{
TextNodetextnode=(TextNode)nodes[i];
Stringline=textnode.toPlainTextString().trim();
if(line.equals(""))
continue;
System.out.println(line);
}
}
/**
*读取一个文件到字符串里.
*
*@paramsFileName文件名
*@paramsEncodeString
*@return文件内容
*/
publicstaticStringreadTextFile(StringsFileName,StringsEncode)
{
StringBuffersbStr=newStringBuffer();
try
{
Fileff=newFile(sFileName);
InputStreamReaderread=newInputStreamReader(newFileInputStream(ff),
sEncode);
BufferedReaderins=newBufferedReader(read);
StringdataLine="";
while(null!=(dataLine=ins.readLine()))
{
sbStr.append(dataLine);
sbStr.append("\r\n");
}
ins.close();
}
catch(Exceptione)
{
LogMan.error("readTextFileError",e);
}
returnsbStr.toString();
}
/**
*去掉左右空格后字符串是否为空
*@paramastrString
*@returnboolean
*/
publicstaticbooleanisTrimEmpty(Stringastr)
{
if((null==astr)||(astr.length()==0))
{
returntrue;
}
if(isBlank(astr.trim()))
{
returntrue;
}
returnfalse;
}
/**
*字符串是否为空:null或者长度为0.
*@paramastr源字符串.
*@returnboolean
*/
publicstaticbooleanisBlank(Stringastr)
{
if((null==astr)||(astr.length()==0))
{
returntrue;
}
else
{
returnfalse;
}
}
}
本小结简单的介绍一下HttpClinet和HtmlParser两个开源的项目,以及他们的网站和提供下载的地址。
HttpClient简介
HTTP协议是现在的因特网最重要的协议之一。除了WEB浏览器之外,WEB服务,基于网络的应用程序以及日益增长的网络计算不断扩展着HTTP协议的角色,使得越来越多的应用程序需要HTTP协议的支持。虽然JAVA类库.net包提供了基本功能,来使用HTTP协议访问网络资源,但是其灵活性和功能远不能满足很多应用程序的需要。而JakartaCommonsHttpClient组件寻求提供更为灵活,更加高效的HTTP协议支持,简化基于HTTP协议的应用程序的创建。HttpClient提供了很多的特性,支持最新的HTTP标准,可以访问这里了解更多关于HttpClinet的详细信息。目前有很多的开源项目都用到了HttpClient提供的HTTP功能,登陆网址可以查看这些项目。本文中使用HttpClinet提供的类库来访问和下载Internet上面的网页,在后续部分会详细介绍到其提供的两种请求网络资源的方法:Get请求和Post请求。Apatche提供免费的HTTPClient源码和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
StringBeansb=newStringBean();
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()方法用来对抽取的链接进行过滤。
下面是各个类的源码,代码中的注释有比较详细的说明。
关键字:htmlparser
需要做一个垂直搜索引擎,比较了nekohtml和htmlparser的功能,尽管nekohtml在容错性、性能等方面的口碑好像比htmlparser好(htmlunit也用的是nekohtml),但感觉nekohtml的测试用例和文档都比htmlparser都少,而且htmlparser基本上能够满足垂直搜索引擎页面处理分析的需求,因此先研究一下htmlparser的使用,有空再研究nekohtml和mozillahtmlparser的使用。
html的功能还是官方说得最为清楚,
引用
HTMLParserisaJavalibraryusedtoparseHTMLineitheralinearornestedfashion.Primarilyusedfortransformationorextraction,itfeaturesfilters,visitors,customtagsandeasytouseJavaBeans.Itisafast,robustandwelltestedpackage.
Thetwofundamentaluse-casesthatarehandledbytheparserareextractionandtransformation(thesynthesesuse-case,whereHTMLpagesarecreatedfromscratch,isbetterhandledbyothertoolsclosertothesourceofdata).Whilepriorversionsconcentratedondataextractionfromwebpages,Version1.4oftheHTMLParserhassubstantialimprovementsintheareaoftransformingwebpages,withsimplifiedtagcreationandediting,andverbatimtoHtml()methodoutput.
研究的重点还是extraction的使用,有空再研究transformation的使用。
1、htmlparser对html页面处理的数据结构
如图所示,HtmlParser采用了经典的Composite模式,通过RemarkNode、TextNode、TagNode、AbstractNode和Tag来描述HTML页面各元素。
*org.htmlparser.Node:
Node接口定义了进行树形结构节点操作的各种典型操作方法,
包括:
节点到html文本、text文本的方法:toPlainTextString、toHtml
典型树形结构遍历的方法:getParent、getChildren、getFirstChild、getLastChild、getPreviousSibling、getNextSibling、getText
获取节点对应的树形结构结构的顶级节点Page对象方法:getPage
获取节点起始位置的方法:getStartPosition、getEndPosition
Visitor方法遍历节点时候方法:accept(NodeVisitorvisitor)
Filter方法:collectInto(NodeListlist,NodeFilterfilter)
Object方法:toString、clone
*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,
2、htmlparser对html页面处理的算法
主要是如下几种方式
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(Stringhtml,Stringcharset)、Parser()、Parser(Lexerlexer,ParserFeedbackfb)、Parser(URLConnectionconnection,ParserFeedbackfb)、Parser(Stringresource,ParserFeedbackfeedback)、Parser(Stringresource)
11.
12.各构造函数的具体用法及含义可以查看其代码,很容易理解。
13.
14.Parser常用的几个方法:
15.
16.*elements获取元素
17.
18.Parserparser=newParser(”http://www.google.com”);
19.for(NodeIteratori=parser.elements();i.hasMoreElements();)
20.processMyNodes(i.nextNode());
21.
22.*parse(NodeFilterfilter):通过NodeFilter方式获取
23.*visitAllNodesWith(NodeVisitorvisitor):通过Nodevisitor方式
24.*extractAllNodesThatMatch(NodeFilterfilter):通过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(NodeFilterfilter)来对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(NodeVisitorvisitor)来对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.importjava.net.URL;
58.
59.importjunit.framework.TestCase;
60.
61.importorg.apache.log4j.Logger;
62.importorg.htmlparser.Node;
63.importorg.htmlparser.NodeFilter;
64.importorg.htmlparser.Parser;
65.importorg.htmlparser.Tag;
66.importorg.htmlparser.beans.LinkBean;
67.importorg.htmlparser.filters.NodeClassFilter;
68.importorg.htmlparser.filters.OrFilter;
69.importorg.htmlparser.filters.TagNameFilter;
70.importorg.htmlparser.tags.HeadTag;
71.importorg.htmlparser.tags.ImageTag;
72.importorg.htmlparser.tags.InputTag;
73.importorg.htmlparser.tags.LinkTag;
74.importorg.htmlparser.tags.OptionTag;
75.importorg.htmlparser.tags.SelectTag;
76.importorg.htmlparser.tags.TableColumn;
77.importorg.htmlparser.tags.TableRow;
78.importorg.htmlparser.tags.TableTag;
79.importorg.htmlparser.tags.TitleTag;
80.importorg.htmlparser.util.NodeIterator;
81.importorg.htmlparser.util.NodeList;
82.importorg.htmlparser.util.ParserException;
83.importorg.htmlparser.visitors.HtmlPage;
84.importorg.htmlparser.visitors.NodeVisitor;
85.importorg.htmlparser.visitors.ObjectFindingVisitor;
86.
87.publicclassParserTestCaseextendsTestCase{
88.
89.privatestaticfinalLoggerlogger=Logger.getLogger(ParserTestCase.class);
90.
91.publicParserTestCase(Stringname){
92.super(name);
93.}
94./*
95.*测试ObjectFindVisitor的用法
96.*/
97.publicvoidtestImageVisitor(){
98.try{
99.ImageTagimgLink;
100.ObjectFindingVisitorvisitor=newObjectFindingVisitor(
101.ImageTag.class);
102.Parserparser=newParser();
103.parser.setURL(”http://www.google.com”);
104.parser.setEncoding(parser.getEncoding());
105.parser.visitAllNodesWith(visitor);
106.Node[]nodes=visitor.getTags();
107.for(inti=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(Exceptione){
118.e.printStackTrace();
119.}
120.}
121./*
122.*测试TagNameFilter用法
123.*/
124.publicvoidtestNodeFilter(){
125.try{
126.NodeFilterfilter=newTagNameFilter(”IMG”);
127.Parserparser=newParser();
128.parser.setURL(”http://www.google.com”);
129.parser.setEncoding(parser.getEncoding());
130.NodeListlist=parser.extractAllNodesThatMatch(filter);
131.for(inti=0;i<list.size();i++){
132.logger.fatal(”testNodeFilter()”+list.elementAt(i).toHtml());
133.}
134.}catch(Exceptione){
135.e.printStackTrace();
136.}
137.
138.}
139./*
140.*测试NodeClassFilter用法
141.*/
142.publicvoidtestLinkTag(){
143.try{
144.
145.NodeFilterfilter=newNodeClassFilter(LinkTag.class);
146.Parserparser=newParser();
147.parser.setURL(”http://www.google.com”);
148.parser.setEncoding(parser.getEncoding());
149.NodeListlist=parser.extractAllNodesThatMatch(filter);
150.for(inti=0;i<list.size();i++){
151.LinkTagnode=(LinkTag)list.elementAt(i);
152.logger.fatal(”testLinkTag()Linkis:”+node.extractLink());
153.}
154.}catch(Exceptione){
155.e.printStackTrace();
156.}
157.
158.}
159./*
160.*测试<linkhref=”text=’text/css’rel=’stylesheet’/>用法
161.*/
162.publicvoidtestLinkCSS(){
163.try{
164.
165.Parserparser=newParser();
166.parser
167..setInputHTML(”<head><title>LinkTest</title>”
168.+“<linkhref=’/test01/css.css’text=’text/css’rel=’stylesheet’/>”
169.+“<linkhref=’/test02/css.css’text=’text/css’rel=’stylesheet’/>”
170.+“</head>”+“<body>”);
171.parser.setEncoding(parser.getEncoding());
172.NodeListnodeList=null;
173.
174.for(NodeIteratore=parser.elements();e.hasMoreNodes();){
175.Nodenode=e.nextNode();
176.logger
177..fatal(”testLinkCSS()”+node.getText()
178.+node.getClass());
179.
180.}
181.}catch(Exceptione){
182.e.printStackTrace();
183.}
184.}
185./*
186.*测试OrFilter的用法
187.*/
188.publicvoidtestOrFilter(){
189.NodeFilterinputFilter=newNodeClassFilter(InputTag.class);
190.NodeFilterselectFilter=newNodeClassFilter(SelectTag.class);
191.ParsermyParser;
192.NodeListnodeList=null;
193.
194.try{
195.Parserparser=newParser();
196.parser
197..setInputHTML(”<head><title>OrFilterTest</title>”
198.+“<linkhref=’/test01/css.css’text=’text/css’rel=’stylesheet’/>”
199.+“<linkhref=’/test02/css.css’text=’text/css’rel=’stylesheet’/>”
200.+“</head>”
201.+“<body>”
202.+“<inputtype=’text’value=’text1′name=’text1′/>”
203.+“<inputtype=’text’value=’text2′name=’text2′/>”
204.+“<select><optionid=’1′>1</option><optionid=’2′>2</option><optionid=’3′></option></select>”
205.+“<ahref=’http://www.yeeach.com’>yeeach.com</a>”
206.+“</body>”);
207.
208.parser.setEncoding(parser.getEncoding());
209.OrFilterlastFilter=newOrFilter();
210.lastFilter.setPredicates(newNodeFilter[]{selectFilter,
211.inputFilter});
212.nodeList=parser.parse(lastFilter);
213.for(inti=0;i<=nodeList.size();i++){
214.if(nodeList.elementAt(i)instanceofInputTag){
215.InputTagtag=(InputTag)nodeList.elementAt(i);
216.logger.fatal(”OrFiltertagnameis:”+tag.getTagName()
217.+”,tagvalueis:”+tag.getAttribute(”value”));
218.}
219.if(nodeList.elementAt(i)instanceofSelectTag){
220.SelectTagtag=(SelectTag)nodeList.elementAt(i);
221.NodeListlist=tag.getChildren();
222.
223.for(intj=0;j<list.size();j++){
224.OptionTagoption=(OptionTag)list.elementAt(j);
225.logger
226..fatal(”OrFilterOption”
227.+option.getOptionText());
228.}
229.
230.}
231.}
232.
233.}catch(ParserExceptione){
234.e.printStackTrace();
235.}
236.}
237./*
238.*测试对<table><tr><td></td></tr></table>的解析
239.*/
240.publicvoidtestTable(){
241.ParsermyParser;
242.NodeListnodeList=null;
243.myParser=Parser.createParser(”<body>”+“<tableid=’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.+“<tableid=’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.NodeFiltertableFilter=newNodeClassFilter(TableTag.class);
253.OrFilterlastFilter=newOrFilter();
254.lastFilter.setPredicates(newNodeFilter[]{tableFilter});
255.try{
256.nodeList=myParser.parse(lastFilter);
257.for(inti=0;i<=nodeList.size();i++){
258.if(nodeList.elementAt(i)instanceofTableTag){
259.TableTagtag=(TableTag)nodeList.elementAt(i);
260.TableRow[]rows=tag.getRows();
261.
262.for(intj=0;j<rows.length;j++){
263.TableRowtr=(TableRow)rows[j];
264.TableColumn[]td=tr.getColumns();
265.for(intk=0;k<td.length;k++){
266.logger.fatal(”<td>”+td[k].toPlainTextString());
267.}
268.
269.}
270.
271.}
272.}
273.
274.}catch(ParserExceptione){
275.e.printStackTrace();
276.}
277.}
278./*
279.*测试NodeVisitor的用法,遍历所有节点
280.*/
281.publicvoidtestVisitorAll(){
282.try{
283.Parserparser=newParser();
284.parser.setURL(”http://www.google.com”);
285.parser.setEncoding(parser.getEncoding());
286.NodeVisitorvisitor=newNodeVisitor(){
287.publicvoidvisitTag(Tagtag){
288.logger.fatal(”testVisitorAll()Tagnameis:”
289.+tag.getTagName()+”\nClassis:”
290.+tag.getClass());
291.}
292.
293.};
294.
295.parser.visitAllNodesWith(visitor);
296.}catch(ParserExceptione){
297.e.printStackTrace();
298.}
299.}
300./*
301.*测试对指定Tag的NodeVisitor的用法
302.*/
303.publicvoidtestTagVisitor(){
304.try{
305.
306.Parserparser=newParser(
307.“<head><title>dddd</title>”
308.+“<linkhref=’/test01/css.css’text=’text/css’rel=’stylesheet’/>”
309.+“<linkhref=’/test02/css.css’text=’text/css’rel=’stylesheet’/>”
310.+“</head>”+“<body>”
311.+“<ahref=’http://www.yeeach.com’>yeeach.com</a>”
312.+“</body>”);
313.NodeVisitorvisitor=newNodeVisitor(){
314.publicvoidvisitTag(Tagtag){
315.if(taginstanceofHeadTag){
316.logger.fatal(”visitTag()HeadTag:Tagnameis:”
317.+tag.getTagName()+”\nClassis:”
318.+tag.getClass()+“\nTextis:”
319.+tag.getText());
320.}elseif(taginstanceofTitleTag){
321.logger.fatal(”visitTag()TitleTag:Tagnameis:”
322.+tag.getTagName()+”\nClassis:”
323.+tag.getClass()+“\nTextis:”
324.+tag.getText());
325.
326.
327.}elseif(taginstanceofLinkTag){
328.logger.fatal(”visitTag()LinkTag:Tagnameis:”
329.+tag.getTagName()+”\nClassis:”
330.+tag.getClass()+“\nTextis:”
331.+tag.getText()+”\ngetAttributeis:”
332.+tag.getAttribute(”href”));
333.}else{
334.logger.fatal(”visitTag():Tagnameis:”
335.+tag.getTagName()+”\nClassis:”
336.+tag.getClass()+“\nTextis:”
337.+tag.getText());
338.}
339.
340.}
341.
342.};
343.
344.parser.visitAllNodesWith(visitor);
345.}catch(Exceptione){
346.e.printStackTrace();
347.}
348.}
349./*
350.*测试HtmlPage的用法
351.*/
352.publicvoidtestHtmlPage(){
353.StringinputHTML=“<html>”+“<head>”
354.+“<title>WelcometotheHTMLParserwebsite</title>”
355.+“</head>”+“<body>”+“WelcometoHTMLParser”
356.+“<tableid=’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.+“<tableid=’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.Parserparser=newParser();
366.try{
367.parser.setInputHTML(inputHTML);
368.parser.setEncoding(parser.getURL());
369.HtmlPagepage=newHtmlPage(parser);
370.parser.visitAllNodesWith(page);
371.logger.fatal(”testHtmlPage-titleis:”+page.getTitle());
372.NodeListlist=page.getBody();
373.
374.for(NodeIteratoriterator=list.elements();iterator
375..hasMoreNodes();){
376.Nodenode=iterator.nextNode();
377.logger.fatal(”testHtmlPage-nodeis:”+node.toHtml());
378.}
379.
380.}catch(ParserExceptione){
381.//TODOAuto-generatedcatchblock
382.e.printStackTrace();
383.}
384.}
385./*
386.*测试LinkBean的用法
387.*/
388.publicvoidtestLinkBean(){
389.Parserparser=newParser();
390.
391.LinkBeanlinkBean=newLinkBean();
392.linkBean.setURL(”http://www.google.com”);
393.URL[]urls=linkBean.getLinks();
394.
395.for(inti=0;i<urls.length;i++){
396.URLurl=urls[i];
397.logger.fatal(”testLinkBean()-urlis:”+url);
398.}
399.
400.}
401.
402.}
packagecn;
importjava.io.BufferedReader;
importjava.io.File;
importjava.io.FileOutputStream;
importjava.io.IOException;
importjava.io.InputStream;
importjava.io.InputStreamReader;
importjava.io.OutputStream;
importjava.net.ConnectException;
importjava.net.MalformedURLException;
importjava.net.URL;
importjava.util.ArrayList;
importjava.util.List;
importjava.util.UUID;
importorg.htmlparser.NodeFilter;
importorg.htmlparser.Parser;
importorg.htmlparser.filters.TagNameFilter;
importorg.htmlparser.tags.ImageTag;
importorg.htmlparser.util.NodeList;
importorg.htmlparser.util.ParserException;
importorg.htmlparser.visitors.HtmlPage;
publicclassgetAll{
privatefinalstaticStringCRLF=System.getProperty("line.separator");//回车换行
publicstaticvoidmakeHtm(intx){
InputStreaminstr=null;
Listlist=newArrayList<String>();
for(;x>89205;x--){
list.clear();
try{
URLur=newURL("你要扒的地址"+x+".html");//这个要按照情况而定了,我不多说了。
try{
System.out.println("正在加载页面:"+ur.toString());
instr=ur.openStream();//获得网页输出流
}catch(ConnectExceptione){
System.out.println(e.toString());
makeHtm(--x);//如果连接超时,将会抛出这个异常并且换成新的网址继续扒。
}
Strings=null;
BufferedReaderin=newBufferedReader(newInputStreamReader(
instr));
StringBuffersb=newStringBuffer();
while((s=in.readLine())!=null){
sb.append(s+CRLF);//读取网页信息,放入字符串缓冲区
}
Parserparser=Parser.createParser(sb.toString(),"utf-8");//获得整个网页的缓冲区创建解析器
HtmlPagepage=newHtmlPage(parser);//把解析器交给解析htmlpage
try{
parser.visitAllNodesWith(page);
}catch(ParserExceptione1){
e1=null;
}
NodeListnodelist=page.getBody();//获得网页的body部分
NodeFilterfilter=newTagNameFilter("IMG");//过滤img标签也可以过滤
//sapn、a等标签
nodelist=nodelist.extractAllNodesThatMatch(filter,true);
for(inti=0;i<nodelist.size();i++){
ImageTaglink=(ImageTag)nodelist.elementAt(i);//获得所有的
//IMG标签
Stringsrc=link.getAttribute("src");//获得img标签的src属性、这个属性就是
//就是那个图片的网址
list.add(src);
/**
*LinkTaglink=(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(MalformedURLExceptione){
e.printStackTrace();
}catch(IOExceptione){
e.printStackTrace();
}
}
System.out.println("下载完成");
}
publicstaticvoiddown(List<String>list,intx)throwsIOException{
Stringsubstring=UUID.randomUUID().toString();
InputStreamin=null;
try{
if(list!=null){
for(Stringsrc:list){
URLurl=newURL(src);
try{
System.out.println("正在下载:"+url.toString());
in=url.openStream();
}catch(ConnectExceptione){
System.out.println(e.toString());
list.clear();
makeHtm(--x);
}
Stringstring=UUID.randomUUID().toString();
Fileforder=newFile("F://fuck//"+substring);
if(!forder.exists()){
forder.mkdir();
}
Filefile=newFile("F://xx//"+substring+"//"+string
+".jpg");//每个网页的图片都放在一个UUID的文件夹里,每个图片都是
//一个UUID的名字
OutputStreamout=newFileOutputStream(file);
byte[]b=newbyte[1024*6];//我习惯这个数字你可以改大点
intlen;
while((len=in.read(b))!=-1){
out.write(b,0,len);//流的对拷,不多说了
out.flush();
}
}
}
}catch(MalformedURLExceptione){
makeHtm(--x);
e.printStackTrace();
}
}
}
当然你别忘记写个main方法调用他
共同学习,共同进步。