client
HttpClient 是 Apache Jakarta Common 下的子项目,可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。
官方站点:http://hc.apache.org/
最新版本4.5 http://hc.apache.org/httpcomponents-client-4.5.x/
官方文档: http://hc.apache.org/httpcomponents-client-4.5.x/tutorial/html/index.html
maven地址:
1 2 3 4 5 | <dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version> 4.5 . 2 </version>
</dependency>
|
HTTP 协议可能是现在 Internet 上使用得最多、最重要的协议了,越来越多的 java 应用程序需要直接通过 HTTP 协议来访问网络资源。
虽然在 JDK 的 java net包中已经提供了访问 HTTP 协议的基本功能,但是对于大部分应用程序来说,JDK 库本身提供的功能还不够丰富和灵活。
HttpClient 是 Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持
HTTP 协议最新的版本和建议。
HttpClient 已经应用在很多的项目中,比如 Apache Jakarta 上很著名的另外两个开源项目 Cactus 和 HTMLUnit 都使用了 HttpClient。
我们搞爬虫的,主要是用HttpClient模拟浏览器请求第三方站点url,然后响应,获取网页数据,然后用Jsoup来提取我们需要的信息;
HttpClient HelloWorld实现
首先建一个Maven项目,然后添加httpClient依赖,版本是4.5
1 2 3 4 5 | <dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version> 4.5 . 2 </version>
</dependency>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | package com.open1111.httpclient;
import java.io.IOException;
import org.apache.http.HttpEntity;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpresponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
public class HelloWorld {
public static void main(String[] args) {
CloseableHttpClient httpClient=HttpClients.createDefault();
HttpGet httpget = new HttpGet( "http://www.open1111.com/" ); // 创建httpget实例
CloseableHttpResponse response= null ;
try {
response = httpClient.execute(httpget);
} catch (ClientProtocolException e) {
e.printstacktrace();
} catch (IOException e) {
e.printStackTrace();
}
HttpEntity entity=response.getEntity();
try {
System.out.println( "网页内容:" +EntityUtils.toString(entity, "utf-8" ));
} catch (ParseException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
|
运行输出:
这里得到了网站首页源码,当然要获得具体数据的话,要用到Jsoup
假如你对这些异常都熟悉 我们可以简化下,异常抛出,这样代码可读性好点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
public class HelloWorld2 {
public static void main(String[] args) throws Exception{
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet httpget = new HttpGet( "http://www.open1111.com/" ); // 创建httpget实例
CloseableHttpResponse response = httpclient.execute(httpget);
HttpEntity entity=response.getEntity();
System.out.println( "网页内容:" +EntityUtils.toString(entity, "utf-8" ));
response.close();
}
}
|
但是实际开发的话,我们对于每一种异常的抛出,catch里都需要做一些业务上的操作,所以以后用的话,还是第一种,
假如爬虫任务很简单,容易爬取,并且量小,那就第二种。还是要根据具体情况来。
HttpClient设置请求头消息User-Agent模拟浏览器
HttpClient设置请求头消息User-Agent模拟浏览器
比如我们请求 www.tuicool.com
用前面的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
public class Demo01 {
public static void main(String[] args) throws Exception{
CloseableHttpClient httpClient=HttpClients.createDefault();
HttpGet httpGet= new HttpGet( "http://www.tuicool.com/" ); // 创建httpget实例
CloseableHttpResponse response=httpClient.execute(httpGet);
HttpEntity entity=response.getEntity();
System.out.println( "网页内容:" +EntityUtils.toString(entity, "utf-8" ));
response.close();
httpClient.close();
}
}
|
返回内容:
网页内容:<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-Type" content="text/html; charset=utf-8">
</head>
<body>
<p>系统检测亲不是真人行为,因系统资源限制,我们只能拒绝你的请求。如果你有疑问,可以通过微博 http://weibo.com/tuicool2012/ 联系我们。</p>
</body>
</html>
我们模拟下浏览器 设置下User-Agent头消息:
// 设置请求头消息User-Agent
httpGet.setHeader("User-Agent", "Mozilla/5.0 (windows NT 6.1; Win64; x64; rv:50.0) Gecko/20100101 Firefox/50.0");
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
public class Demo01 {
public static void main(String[] args) throws Exception{
CloseableHttpClient httpClient=HttpClients.createDefault();
HttpGet httpGet= new HttpGet( "http://www.tuicool.com/" ); // 创建httpget实例
httpGet.setHeader( // 设置请求头消息User-Agent
"User-Agent" ,
"Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:50.0) Gecko/20100101 Firefox/50.0" );
CloseableHttpResponse response=httpClient.execute(httpGet);
HttpEntity entity=response.getEntity();
System.out.println( "网页内容:" +EntityUtils.toString(entity, "utf-8" ));
response.close();
httpClient.close();
}
}
|
运行 :
当然通过火狐firebug,我们还可以看到其他请求头消息:
都是可以通过setHeader方法 设置key value;来得到模拟浏览器请求;
HttpClient获取响应内容类型Content-Type
HttpClient获取响应内容类型Content-Type
响应的网页内容都有类型也就是Content-Type
通过火狐firebug,我们看响应头信息:
当然我们可以通过HttpClient接口来获取;
HttpEntity的getContentType().getValue() 就能获取到响应类型;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
public class Demo2 {
public static void main(String[] args) throws Exception{
CloseableHttpClient httpClient=HttpClients.createDefault();
HttpGet httpGet= new HttpGet( "http://www.java1234.com" ); // 创建httpget实例
httpGet.setHeader( // 设置请求头消息User-Agent
"User-Agent" ,
"Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:50.0) Gecko/20100101 Firefox/50.0" );
CloseableHttpResponse response=httpClient.execute(httpGet);
HttpEntity entity=response.getEntity();
System.out.println( "Content-Type:" +entity.getContentType().getValue());
response.close();
httpClient.close();
}
}
|
运行输出:Content-Type:text/html
一般网页是text/html当然有些是带编码的,比如请求www.tuicool.com:输出:Content-Type:text/html; charset=utf-8
假如请求js文件,比如 http://www.open1111.com/static/js/jQuery.js运行输出:Content-Type:APPlication/JavaScript
假如请求的是文件,比如 http://central.maven.org/maven2/HTTPClient/HTTPClient/0.3-3/HTTPClient-0.3-3.jar
运行输出:Content-Type:application/java-archive
当然Content-Type还有一堆,那这东西对于我们爬虫有啥用的,
我们再爬取网页的时候 ,可以通过Content-Type来提取我们需要爬取的网页或者是爬取的时候,需要过滤掉的一些网页;
HttpClient获取响应状态Status
我们HttpClient向服务器请求时,
正常情况 执行成功 返回200状态码,
不一定每次都会请求成功,比如这个请求地址不存在 返回404
服务器内部报错 返回500
有些服务器有防采集,假如你频繁的采集数据,则返回403 拒绝你请求。
当然 我们是有办法的 后面会讲到用代理IP。
这个获取状态码,我们可以用 CloseableHttpResponse对象的getStatusLine().getStatusCode()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | package com.open1111.httpclient.chap02;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
public class Demo3 {
public static void main(String[] args) throws Exception{
CloseableHttpClient httpClient=HttpClients.createDefault();
HttpGet httpGet= new HttpGet( "http://www.open1111.com" ); // 创建httpget实例
httpGet.setHeader( "User-Agent" , "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:50.0) Gecko/20100101 Firefox/50.0" );
CloseableHttpResponse response=httpClient.execute(httpGet);
System.out.println( "Status:" +response.getStatusLine().getStatusCode());
HttpEntity entity=response.getEntity();
System.out.println( "Content-Type:" +entity.getContentType().getValue());
response.close();
httpClient.close();
}
}
|
运行输出:
Status:200
Content-Type:text/html;charset=UTF-8
假如换个页面 http://www.open1111.com/aaa.jsp
因为不存在,所以返回 404
HttpClient使用代理IP
在爬取网页的时候,有的目标站点有反爬虫机制,对于频繁访问站点以及规则性访问站点的行为,会采集屏蔽IP措施。
这时候,代理IP就派上用场了。
关于代理IP的话 也分几种 透明代理、匿名代理、混淆代理、高匿代理
1、透明代理(Transparent Proxy)
REMOTE_ADDR = Proxy IP
HTTP_VIA = Proxy IP
HTTP_X_FORWARDED_FOR = Your IP
透明代理虽然可以直接“隐藏”你的IP地址,但是还是可以从HTTP_X_FORWARDED_FOR来查到你是谁。
2、匿名代理(Anonymous Proxy)
REMOTE_ADDR = proxy IP
HTTP_VIA = proxy IP
HTTP_X_FORWARDED_FOR = proxy IP
匿名代理比透明代理进步了一点:别人只能知道你用了代理,无法知道你是谁。
还有一种比纯匿名代理更先进一点的:混淆代理,见下节。
3、混淆代理(Distorting Proxies)
REMOTE_ADDR = Proxy IP
HTTP_VIA = Proxy IP
HTTP_X_FORWARDED_FOR = Random IP address
如上,与匿名代理相同,如果使用了混淆代理,别人还是能知道你在用代理,但是会得到一个假的IP地址,伪装的更逼真:-)
4、高匿代理(Elite proxy或High Anonymity Proxy)
REMOTE_ADDR = Proxy IP
HTTP_VIA = not determined
HTTP_X_FORWARDED_FOR = not determined
可以看出来,高匿代理让别人根本无法发现你是在用代理,所以是最好的选择。
一般我们搞爬虫 用的都是 高匿的代理IP;
那代理IP 从哪里搞呢 很简单 百度一下,你就知道 一大堆代理IP站点。 一般都会给出一些免费的,但是花点钱搞收费接口更加方便;
比如 http://www.66ip.cn/
httpClient使用代理IP代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | package com.open1111.httpclient.chap04;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.client.config.requestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
public class Demo1 {
public static void main(String[] args) throws Exception {
CloseableHttpClient httpClient=HttpClients.createDefault();
HttpGet httpGet= new HttpGet( "https://www.taobao.com/" ); // 创建httpget实例
HttpHost proxy= new HttpHost( "116.226.217.54" , 9999 );
RequestConfig requestConfig=RequestConfig.custom().setProxy(proxy).build();
httpGet.setConfig(requestConfig);
httpGet.setHeader(
"User-Agent" , "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:50.0) Gecko/20100101 Firefox/50.0" );
CloseableHttpResponse response=httpClient.execute(httpGet);
HttpEntity entity=response.getEntity();
System.out.println( "网页内容:" +EntityUtils.toString(entity, "utf-8" ));
response.close();
httpClient.close();
}
}
|
建议大家用国内代理IP 以及主干道网络大城市的代理IP 访问速度快;
HttpClient连接超时及读取超时
HttpClient连接超时及读取超时
httpClient在执行具体http请求时候 有一个连接的时间和读取内容的时间;
HttpClient连接时间
所谓连接的时候 是HttpClient发送请求的地方开始到连接上目标url主机地址的时间,理论上是距离越短越快,线路越通畅越快,
但是由于路由复杂交错,往往连接上的时间都不固定,运气不好连不上,
HttpClient的默认连接时间,据我测试,默认是1分钟,假如超过1分钟 过一会继续尝试连接,这样会有一个问题 假如遇到一个url老是连不上,会影响其他线程的线程进去,所以我们有必要进行特殊设置,比如设置10秒钟 假如10秒钟没有连接上 我们就报错,这样我们就可以进行业务上的处理,比如我们业务上控制 过会再连接试试看。并且这个特殊url写到log4j日志里去。方便管理员查看。
HttpClient读取时间
所谓读取的时间 是HttpClient已经连接到了目标服务器,然后进行内容数据的获取,一般情况 读取数据都是很快速的,
但是假如读取的数据量大,或者是目标服务器本身的问题(比如读取数据库速度慢,并发量大等等..)也会影响读取时间。
同上,我们还是需要来特殊设置下,比如设置10秒钟 假如10秒钟还没读取完,就报错,同上,我们可以业务上处理。
比如我们这里给个地址 http://central.maven.org/maven2/这个是国外地址 连接时间比较长的,而且读取的内容多
很容易出现连接超时和读取超时;
我们如何用代码实现呢?
HttpClient给我们提供了一个RequestConfig类 专门用于配置参数比如连接时间,读取时间以及前面讲解的代理IP等。
这里给下示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
public class Demo2 {
public static void main(String[] args) throws Exception {
CloseableHttpClient httpClient=HttpClients.createDefault();
HttpGet httpGet= new HttpGet( "http://central.maven.org/maven2/" ); // 创建httpget实例
RequestConfig config=RequestConfig.custom()
.setConnectTimeout( 5000 )
.setsocketTimeout( 5000 )
.build();
httpGet.setConfig(config);
httpGet.setHeader(
"User-Agent" , "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:50.0) Gecko/20100101 Firefox/50.0" );
CloseableHttpResponse response=httpClient.execute(httpGet);
HttpEntity entity=response.getEntity();
System.out.println( "网页内容:" +EntityUtils.toString(entity, "utf-8" ));
response.close();
httpClient.close();
}
}
|
相关阅读
【HTTPClient】HttpClient框架详解
【HTTPClient】HttpClient框架详解
2016年12月24日 15:42:08
阅读数:4293
HttpClient简介
HTTP 协议可能是现在 Internet 上使