java实现的简单网页爬虫:Servlet 搜索引擎核心爬虫程序(三)

/**
 *
 * @author Administrator
 *
 * JavaSpider 1.6 版本
 *
 * 1,对所有的目标网址进行抽取,得到目标java文件,也就是我们需要的java源文件;
 * 2,将所有的java源文件保存到对应的java文件中,保存到本地硬盘的指定目录下;
 * 3,我们需要一个java工具类,或者方法,用来生成唯一的java源文件名称;
 *
 */

到这里,我们通过这几个修改和完善的版本,基本上可以完成实现了从指定站点获取源代码的功能。

一,新建java web项目

项目名称:JavaSpider_2016
版本:JavaSpider 1.6

二,项目采用servlet + MySQL 5.5

jar包所在位置:/JavaSpider_2016/WebRoot/WEB-INF/lib
配置文件所在位置:/JavaSpider_2016/WebRoot/WEB-INF/web.xml
图片所在位置:/JavaSpider_2016/WebRoot/images
CSS文件所在位置:/JavaSpider_2016/WebRoot/CSS

三,数据库建表语句

数据库.txt文件中

四,访问项目首页

http://localhost:8890/JavaSpider_2016  
或者
http://localhost:8890/JavaSpider_2016/index.jsp

1,如果不是在本机测试,请把localhost换成服务器所在的电脑的IP地址

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;
	
}

/JavaSpider_2016/src/com/spider/java/JavaSpider_1_6.java   爬虫系统核心接口实现类

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();
			}
		}

	}
}

/JavaSpider_2016/src/com/spider/java/JavaSpider_1_6_HTMLParser.java  HTML页面内容解析、抽取工具类

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);
		
	}
	
}

/JavaSpider_2016/src/com/spider/java/JavaSpider_1_6_HTMLParserUtil_Escape.java  HTML页面解析、抽取工具类(转义字符)

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;
        
    }
}

/JavaSpider_2016/src/com/spider/java/JavaSpider_1_6_HTMLParserUtil_GenerateFileName.java  生成文件名称工具类

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;
	}
}

/JavaSpider_2016/src/com/spider/java/JavaSpider_1_6_URLParser.java  URL连接处理工具类

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());

FileOutputStream 在读文件时,是以字节为单位来读取的,对字符串进行了转换,所有要进行换行操作。


3,网页HTML元素的解析问题。这个情况比较复杂,我这里只是考虑的简单的情况,也就是我实际抽取的网页内容的情况。如果想让代码更健壮,我们还要考虑更多更复杂的情况,这里因为只是演示简单的爬虫,没有搞的很复杂,大家如果有需要,可以进行扩展。


稍后还会继续更新爬虫的其他完善功能...


下面是几张效果图:

首页:

java实现的简单网页爬虫:Servlet 搜索引擎核心爬虫程序(三)_第1张图片


版本1.6的主要功能:

java实现的简单网页爬虫:Servlet 搜索引擎核心爬虫程序(三)_第2张图片


抽取的部分java源代码文件截图:

java实现的简单网页爬虫:Servlet 搜索引擎核心爬虫程序(三)_第3张图片


源代码内容示例:

java实现的简单网页爬虫:Servlet 搜索引擎核心爬虫程序(三)_第4张图片


OK,今天就到这里。源代码地址:http://download.csdn.net/detail/reggergdsg/9407071


你可能感兴趣的:(java实现的简单网页爬虫:Servlet 搜索引擎核心爬虫程序(三))