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