2,tomcat端口如果不是8890,请把8890改成你的tomcat的端口
下面贴出几个关键代码,其他的完整的文件,可以到资源中下载:
http://download.csdn.net/detail/reggergdsg/9407071
/JavaSpider_2016/src/com/spider/java/JavaSpiderBase_1_6.java 爬虫系统核心接口
package com.spider.java; import java.io.IOException; import org.apache.http.client.ClientProtocolException; /** * * @author Administrator * * JavaSpider 1.6 版本 * * 1,对所有的目标网址进行抽取,得到目标java文件,也就是我们需要的java源文件; * 2,将所有的java源文件保存到对应的java文件中,保存到本地硬盘的指定目录下; * 3,我们需要一个java工具类,或者方法,用来生成唯一的java源文件名称; * */ public interface JavaSpiderBase_1_6 { //带参数的方法 JavaSpiderBase_1_6版本 public void getFormatCode_1_6(String URL) throws ClientProtocolException, IOException; }
package com.spider.java; import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; /** * * @author Administrator * * JavaSpider 1.6 版本 * * 1,对所有的目标网址进行抽取,得到目标java文件,也就是我们需要的java源文件; * 2,将所有的java源文件保存到对应的java文件中,保存到本地硬盘的指定目录下; * 3,我们需要一个java工具类,或者方法,用来生成唯一的java源文件名称; * */ @SuppressWarnings("deprecation") public class JavaSpider_1_6 implements JavaSpiderBase_1_6 { //定义一个字符串常量,用来表示文件保存的路径 private final static String FILE_PATH = "E:/java_source_file/"; //对网页进行爬取,并进行html解析,获取源代码,保存到java文件中 @Override public void getFormatCode_1_6(String URL) throws ClientProtocolException, IOException { //创建HttpClient HttpClient httpClient = new DefaultHttpClient(); //获取HttpGet对象 HttpGet httpGet = new HttpGet(URL); // @SuppressWarnings("unused") StringBuffer stringBuffer = new StringBuffer(); // HttpResponse httpResoponse = httpClient.execute(httpGet); // BufferedReader bufferedReader; //定义一个Map,用来封装所有的URL //Map<Integer,String> urls = new HashMap<Integer,String>(); //生成JavaSpider_1_6_HTMLParser对象 JavaSpider_1_6_HTMLParser javaSpider_1_6_HTMLParser = new JavaSpider_1_6_HTMLParser(); /* * 调用 JavaSpider_1_6_HTMLParserUtil_GenerateFileName ,生成文件名称 */ JavaSpider_1_6_HTMLParserUtil_GenerateFileName generateFileName = new JavaSpider_1_6_HTMLParserUtil_GenerateFileName(); //生成一个File对象 File file = new File(FILE_PATH + generateFileName.javaSpider_HTMLParserUtil_GenerateFileName(URL)); //创建文件 if(!file.exists()){ file.createNewFile(); //测试输出 System.out.println("文件创建成功 :" + generateFileName.javaSpider_HTMLParserUtil_GenerateFileName(URL)); } else{ //测试输出 System.out.println("文件名已存在 !" + generateFileName.javaSpider_HTMLParserUtil_GenerateFileName(URL)); } if(HttpStatus.SC_OK == httpResoponse.getStatusLine().getStatusCode()){ // HttpEntity httpEntity = httpResoponse.getEntity(); // if(httpEntity != null){ bufferedReader = new BufferedReader(new InputStreamReader(httpEntity.getContent(),"UTF-8")); //bufferedReader按行读取 String line = ""; //if(httpEntity.getContentLength() > 0 ){ if(httpEntity.getContent() != null && httpEntity.getContentLength() > 0){ stringBuffer = new StringBuffer((int) httpEntity.getContentLength()); //文件输出流 FileOutputStream fileOutputStream = new FileOutputStream(file); while((line = bufferedReader.readLine()) != null){ //判断得到的目标网址是否为空 if(!"".equals(javaSpider_1_6_HTMLParser.parserHTML(line))){ //对网页进行解析抽取 //javaSpider_1_6_HTMLParser.parserHTML(line); //保存到文件 fileOutputStream.write((javaSpider_1_6_HTMLParser.parserHTML(line) + "\r\n" ).getBytes()); } } } //如果httpEntity.getContent() != null && httpEntity.getContentLength() == -1 else{ //测试输出 System.out.println("进入if...进入条件:httpEntity.getContent() != null || httpEntity.getContentLength() == -1"); //stringBuffer = new StringBuffer((int) httpEntity.getContentLength()); //把长度写死 stringBuffer = new StringBuffer(1024); //文件输出流 FileOutputStream fileOutputStream = new FileOutputStream(file); while((line = bufferedReader.readLine()) != null){ //判断得到的目标网址是否为空 if(!"".equals(javaSpider_1_6_HTMLParser.parserHTML(line))){ //对网页进行解析抽取 //javaSpider_1_6_HTMLParser.parserHTML(line); //保存到文件 fileOutputStream.write((javaSpider_1_6_HTMLParser.parserHTML(line) + "\r\n" ).getBytes()); } } } } if(httpEntity != null){ // httpEntity.consumeContent(); } } } }
package com.spider.java; /** * * @author Administrator * * JavaSpider 1.6 版本 * * 1,对所有的目标网址进行抽取,得到目标java文件,也就是我们需要的java源文件; * 2,将所有的java源文件保存到对应的java文件中,保存到本地硬盘的指定目录下; * 3,我们需要一个java工具类,或者方法,用来生成唯一的java源文件名称; * */ public class JavaSpider_1_6_HTMLParser { //生成页面抽取工具类 JavaSpider_1_6_HTMLParserUtil 对象 JavaSpider_1_6_HTMLParserUtil_Escape javaSpider_1_6_HTMLParserUtil_Escape= new JavaSpider_1_6_HTMLParserUtil_Escape(); // public String parserHTML(String line){ //定义一个String类型的变量parseredLine,用来表示处理以后的line String parseredLine = ""; //第一次抽取后的子串 String subString = ""; //第二次抽取后的子串 String sub_subString = ""; //第三次抽取后的子串 String sub_sub_subString = ""; int i = line.indexOf('<'); int j = line.lastIndexOf('<'); int k = line.indexOf('>'); //1,如果字符<第一次出现的索引和最后一次出现的索引值相等,说明这一行,只有一对<></> 这种闭合的HTML标签; //此时只需要把这个标签删除掉就行,我们可以使用String类的subString方法截取我们需要的信息; if(i == j && i != -1){ //这种情况下, 我们还要再判断,这个标签是不是位于行首; if(i == 0 ){ //System.out.println(""); //简化处理 } else{ //System.out.println(""); //简化处理,暂时不考虑<br>这种单独的标签 } } //如果字符< 第一次出现的索引和最后一次出现的索引值不相同,说明这一行,有2对<></>或者多对, 这样的闭合的HTML标签; //2,如果有2对闭合的HTML标签;此时我们需要删除这2对HTML标签;这里简化步骤,只考虑闭合标签位于首尾的情况; else if(i != j){ //第一次抽取 subString = line.substring(k+1, j); //第二次抽取 //第二次抽取的时候,需要考虑2个标签的特殊情况,也就是title、link这种标签,虽然符合条件,但是不抽取这种值。 int y = subString.lastIndexOf('<'); int z = subString.indexOf('>'); if(y > -1){ //此时还要考虑只有3个HTML标签的特殊情况 if(subString.contains("<title") || subString.contains("<link" )){ sub_subString = subString.substring(z+1, y); } else{ sub_subString = subString.substring(z+1, y); if(sub_subString != null && (sub_subString.startsWith("0") || sub_subString.startsWith("1") || sub_subString.startsWith("2") || sub_subString.startsWith("3") || sub_subString.startsWith("4") || sub_subString.startsWith("5") || sub_subString.startsWith("6") || sub_subString.startsWith("7") || sub_subString.startsWith("8") || sub_subString.startsWith("9"))){ } else{ System.out.println(sub_subString); parseredLine = sub_subString; } } } //第三次抽取 int A = sub_subString.indexOf('<'); int B = sub_subString.indexOf('>'); int C = sub_subString.lastIndexOf('<'); //如果A<0,说明没有HTML标签了; if(A < 0){ //System.out.println(""); } //如果A>0,说明还有HTML标签,此时需要判断是只有一个,还是有多个; else{ //如果A = C,说明,只有一个HTML标签,此时还有三种情况,HTML标签在首,HTML标签居中,HTML标签在尾; if(A == C && A == 0){ sub_sub_subString = sub_subString.substring(B+1, sub_subString.length()); System.out.println(sub_sub_subString); parseredLine = sub_sub_subString; } else if(A == C && (B == sub_subString.length() - 1)){ sub_sub_subString = sub_subString.substring(0, A); System.out.println(sub_sub_subString); parseredLine = sub_sub_subString; } else if(A == C && A != 0 && (B != sub_subString.length() - 1 )){ //如果HTML标签居中,我们这时需要根据java的语法来判断, //此时还需要判断,我们需要抽取的内容在哪边,这时我们根据HTML标签内,有没有/来判断 //如果书写规范的话,没有/,则我们需要抽取的内容在后边;否则在前边; //这种情况下,还要进行第四次抽取的判断; //如果开头是数字,可以判断我们需要抽取的代码在尾部 if(sub_subString.substring(0, 1).matches("^[0-9]")){ sub_sub_subString = sub_subString.substring(B+1,sub_subString.length()); System.out.println(sub_sub_subString); parseredLine = sub_sub_subString; } else{ sub_sub_subString = sub_subString.substring(0, A); System.out.println(sub_sub_subString); parseredLine = sub_sub_subString; } } } } //调用 页面抽取工具类,处理html转义字符,然后返回 return javaSpider_1_6_HTMLParserUtil_Escape.javaSpider_HTMLParser_Escape(parseredLine); } }
package com.spider.java; /** * * @author Administrator * * JavaSpider 1.6 版本 * * 1,对所有的目标网址进行抽取,得到目标java文件,也就是我们需要的java源文件; * 2,将所有的java源文件保存到对应的java文件中,保存到本地硬盘的指定目录下; * 3,我们需要一个java工具类,或者方法,用来生成唯一的java源文件名称; * */ //页面抽取工具类,处理html转义字符 public final class JavaSpider_1_6_HTMLParserUtil_Escape { //无参数构造方法 public JavaSpider_1_6_HTMLParserUtil_Escape(){ } // public String javaSpider_HTMLParser_Escape(String parseredLine){ //定义一个字符串String,用来表示处理以后的最终字符串 String final_line = ""; final_line = parseredLine.replaceAll("<", "<").replaceAll(">", ">").replaceAll("&", "&").replaceAll(""", "\""); //返回处理结果 return final_line; } }
package com.spider.java; /** * * @author Administrator * * JavaSpider 1.6 版本 * * 1,对所有的目标网址进行抽取,得到目标java文件,也就是我们需要的java源文件; * 2,将所有的java源文件保存到对应的java文件中,保存到本地硬盘的指定目录下; * 3,我们需要一个java工具类,或者方法,用来生成唯一的java源文件名称; * */ public final class JavaSpider_1_6_HTMLParserUtil_GenerateFileName { //定义一个字符串常量,用来表示生成的文件名称的后缀 private final static String FILE_NAME_SUFFIX = ".java"; //无参数构造方法 public JavaSpider_1_6_HTMLParserUtil_GenerateFileName(){ } //网页抽取工具类,生成文件名称 public String javaSpider_HTMLParserUtil_GenerateFileName(String URL){ //定义一个整型变量,用来表示URL中,最后一个.的索引 int last_point_index = URL.lastIndexOf("."); //定义一个整型变量,用来表示URL中,最后一个/的索引 int last_line_index = URL.lastIndexOf("/"); return URL.substring(last_line_index + 1, last_point_index - 1) + FILE_NAME_SUFFIX; } }
package com.spider.java; /** * * @author Administrator * * JavaSpider 1.6 版本 * * 1,对所有的目标网址进行抽取,得到目标java文件,也就是我们需要的java源文件; * 2,将所有的java源文件保存到对应的java文件中,保存到本地硬盘的指定目录下; * 3,我们需要一个java工具类,或者方法,用来生成唯一的java源文件名称; * */ public class JavaSpider_1_6_URLParser { /** * 实现方法: * * 1,直接获取第一个A标签的起始位置,然后截取想要的属性,或者A标签; * 2,然后从剩下的二级子串中,重复进行第一步的操作; * 3,以此类推,我们就可以获取所有的A标签了... * * 此方法需要接收以下几个参数: * 1,当前页面的网址current_url,String类型; * 2,当前需要处理的行line,String类型; */ public String parserURL(String line,String current_url){ //目标网址前缀 target_url_prefix String target_url_prefix = ""; //目标网址 String target_url = ""; //目标网址后缀 String target_url_suffix = ""; /* * 第一次抽取 */ //定义一个int变量,用来表示第一个 A 标签起始位置的索引 int a_start = -100; //定义一个int变量,用来表示第一个 A 标签的 href 属性起始位置的索引 int href_start = -100; //定义一个int变量,用来表示第一个 A 标签的 第一个双引号 起始位置的索引 int double_start = -100; //定义一个String类型的变量,用来表示截取的子串,我们称之为一级子串 String sub_String = ""; //定义一个String类型的变量,用来表示截取的子串的子串,我们称之为二级子串 String sub_sub_String = ""; /* * 首先对当前网址current_url进行处理,获得目标网址前缀 */ int current_url_index = current_url.lastIndexOf("/"); target_url_prefix = current_url.substring(0, current_url_index+1); //测试输出 //System.out.println("当前输入的URL ==== " + current_url); //System.out.println("目标网址前缀 target_url_prefix ==== " + target_url_prefix); //获取第一个A标签的索引 if(line.contains("<a")){ a_start = line.indexOf("<a"); sub_String = line.substring(a_start); //测试输出 System.out.println("一级子串 sub_String = " + sub_String); href_start = sub_String.indexOf("href="); sub_sub_String = sub_String.substring(href_start+6); //测试输出 System.out.println("二级子串 sub_sub_String = " + sub_sub_String); //如果二级子串非法,也就是href的第一位不是字母 if(sub_sub_String.startsWith("?") || sub_sub_String.startsWith("/")){ //测试输出 System.out.println("非法网址,不保存!"); } else{ double_start = sub_sub_String.indexOf("\""); target_url_suffix = sub_sub_String.substring(0, double_start); //测试输出 System.out.println("目标网址后缀 target_url_suffix = " + target_url_suffix); } } //如果目标网址后缀 target_url_suffix 不为空 if(!"".equals(target_url_suffix)){ //目标网址为 target_url = target_url_prefix + target_url_suffix; //测试输出 //System.out.println("当前获得的目标网址为 target_url:" + target_url); } //返回目标网址 return target_url; } }
1,在对HTML的转义字符进行处理时,由于HTML的转义字符有很多,我在这里,没有把所有的转义字符都处理掉,只挑选了几个最常用的,也是在处理这个站点的页面时遇到的几个转义字符。比如大于号、小于号、双引号、逻辑与符号。
2,在把抽取的网页内容写入文件的操作中,换行的问题。由于我们保存的是java文件,而java文件,在windows下和txt文件是一样来显示的,所以我们可以使用 \r\n 来作为换行符,代码如下:
fileOutputStream.write((javaSpider_1_6_HTMLParser.parserHTML(line) + "\r\n" ).getBytes());
3,网页HTML元素的解析问题。这个情况比较复杂,我这里只是考虑的简单的情况,也就是我实际抽取的网页内容的情况。如果想让代码更健壮,我们还要考虑更多更复杂的情况,这里因为只是演示简单的爬虫,没有搞的很复杂,大家如果有需要,可以进行扩展。
稍后还会继续更新爬虫的其他完善功能...
下面是几张效果图:
首页:
版本1.6的主要功能:
抽取的部分java源代码文件截图:
源代码内容示例:
OK,今天就到这里。源代码地址:http://download.csdn.net/detail/reggergdsg/9407071