crawler学习篇(jar爬取)

新建maven项目

导入依赖的jar包

<dependencies>
		<!-- 添加Httpclient支持 -->
		<dependency>
			<groupId>org.apache.httpcomponents</groupId>
			<artifactId>httpclient</artifactId>
			<version>4.5.2</version>
		</dependency>

		<!-- 添加jsoup支持 -->
		<dependency>
			<groupId>org.jsoup</groupId>
			<artifactId>jsoup</artifactId>
			<version>1.10.1</version>
		</dependency>

		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.16</version>
		</dependency>

	</dependencies>

 

需要爬取的网址 :http://central.maven.org/

/**
 * 爬取网络资源的类
 * @author Admin
 *
 *1、通过httpclient和jsoup爬取网页,分析所有url
 *2、过滤无效url,迭代解析
 *3、利用异步线程池对爬取的性能进行优化
 *
 */
public class StartCrawler {
	
	// 要过滤掉的url后缀
	public static String[] excludeUrls = new String[] { ".pom", ".xml", ".md5", ".sha1", ".asc", ".gz", ".zip", "../" };
	//队列   先进先出
	public static Queue<String> waitForCrawlerUrls = new LinkedList<String>();// 等待再次爬取的Url
	public static long total = 0;//计数
	public static boolean exeFlag = true;//默认解析爬取队列里面的网址
	

	/**
	 * 通过网址url,利用httpclient技术,获得当前url对应的网络内容
	 * @param url
	 */
//	public static void parseUrl(String url,String realDir) {
	public static void parseUrl() {
//		利用异步线程池   对爬取的性能进行优化
		//存放10个异步线程的线程池
		ExecutorService executorService = Executors.newFixedThreadPool(10);//实例化一个线程池 池中放10个线程
		while(exeFlag) {//需要满足的条件
			if(waitForCrawlerUrls.size() > 0) {//队列里有链接
				executorService.execute(new Runnable() {
					//使用线程池中的异步执行解析逻辑
					public void run() {
						
						while(waitForCrawlerUrls.size() > 0) {
							String url = waitForCrawlerUrls.poll();//(队列当中的取值)摘取队列的第一个元素,并且移除
							
							//CloseableHttpClient可以被用于从客户端发送HTTP请求到服务端
							CloseableHttpClient httpClient = HttpClients.createDefault();//获取httpclient的一个实例
							HttpGet httpGet = new HttpGet(url);//获得是什么请求
							//设置连接时长5秒和等待服务器响应数据时长8秒
							RequestConfig config = RequestConfig.custom().setConnectTimeout(5000).setSocketTimeout(8000).build();
							httpGet.setConfig(config);
							CloseableHttpResponse response = null;
							
							//执行
							try {
								//要抓异常是因为避免访问超时
								response = httpClient.execute(httpGet);
								if(response != null) {
									HttpEntity entity = response.getEntity();//获取内容
									//凡是text/html(网页)这一类型的需要进行再次解析
									if("text/html".equals(entity.getContentType().getValue())) {
										String pageContent = EntityUtils.toString(entity,"utf-8");//获取网页内容
										parsePageContent(pageContent,url);//再次解析页面的内容
									}

								}else {//未得到响应
									System.out.println("连接时间过长");
									addUrl(url);//再次把链接加到队列当中去
								}
								
							} catch (ClientProtocolException e) {
								e.printStackTrace();
							} catch (IOException e) {
								e.printStackTrace();
							}finally {
								try {
									if(response != null) {
										response.close();
									}
									
									if(httpClient != null) {
										httpClient.close();
									}
									
								} catch (IOException e) {
									e.printStackTrace();
								}
							}
						}
						
					}
				});
			}else {//队列里没有链接
				if(((ThreadPoolExecutor)executorService).getActiveCount() == 0) {//要求线程池中没有还在执行的线程
					exeFlag = false;
					break;
				}
			}
		}
		
		//避免解析不过来让线程休眠
		try {
			Thread.sleep(1000);//(给线程解析的时间,避免出现问题)
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
	}
	
	/**
	 * 通过网页爬虫爬虫框架jsoup对网页内容进行解析(再次解析页面的内容)
	 * @param pageContent
	 */
	public static void parsePageContent(String pageContent,String realDir) {
		Document doc = Jsoup.parse(pageContent);//jsp页面中的doc树
		Elements aEles = doc.select("a");//通过doc获取a标签
		for (Element aEle : aEles) {
			String aHref = aEle.attr("href");
//			System.out.println(realDir + aHref);//所有的链接地址
			
			String url = realDir + aHref;
			/**
			 * 链接分为三种(以这个为例)
			 * 目标链接(jar)
			 * 过滤的链接(不需要的链接)
			 * 迭代解析的链接(需要再次解析的链接)
			 */
			
			if(null == url || "".equals(url) ) return;
			
			boolean f = true;//默认就是我想要的链接
			for (String excludeUrl : excludeUrls) {
				if(url.endsWith(excludeUrl)) {//url.endsWith(excludeUrl)  链接url以excludeUrl结尾
					f = false;//不是需要的链接
					break;
				}
			}
			
			if(f && url.endsWith(".jar")) {
				System.out.println("爬了第"+(++total)+"个目标,链接地址url为:"+ url);
			}else {//迭代解析的链接
				addUrl(url);//加入到队列里面去,需要再一次爬取的
			}
		}
	}

	/**
	 * 添加到爬虫队列里面,等待再一次爬取
	 * @param url
	 */
	private static void addUrl(String url) {
		System.out.println(url + "添加成功");
		waitForCrawlerUrls.add(url);
	}
	
	/**
	 * 给队列提供初始值
	 */
	public static void init() {
		String url = "http://central.maven.org/maven2/HTTPClient/HTTPClient/";
		addUrl(url);
		addUrl("http://central.maven.org/maven2/commons-cli/commons-cli/");
		parseUrl();
	}
	

	public static void main(String[] args) {
		init();
	}
	
	//未进行优化的代码
	public static void version1() {

		//链接地址来自于队列当中
		while(waitForCrawlerUrls.size() > 0) {
			String url = waitForCrawlerUrls.poll();//(队列当中的取值)摘取队列的第一个元素,并且移除
			
			//CloseableHttpClient可以被用于从客户端发送HTTP请求到服务端
			CloseableHttpClient httpClient = HttpClients.createDefault();//获取httpclient的一个实例
			HttpGet httpGet = new HttpGet(url);//获得是什么请求
			CloseableHttpResponse response = null;
			
			//执行
			try {
				//要抓异常是因为避免访问超时
				response = httpClient.execute(httpGet);
				HttpEntity entity = response.getEntity();//获取内容
//				System.out.println(entity.getContentType().toString());
//				System.out.println(entity.getContentType().getValue());
				//凡是text/html(网页)这一类型的需要进行再次解析
				if("text/html".equals(entity.getContentType().getValue())) {
					String pageContent = EntityUtils.toString(entity,"utf-8");//获取网页内容
					parsePageContent(pageContent,url);//再次解析页面的内容
//					System.out.println(pageContent);
				}
				
			} catch (ClientProtocolException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}finally {
				try {
					if(response != null) {
						response.close();
					}
					
					if(httpClient != null) {
						httpClient.close();
					}
					
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
	}
	
	
}

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值