Java HttpClient使用小结

1、使用连接池

虽说http协议时无连接的,但毕竟是基于tcp的,底层还是需要和服务器建立连接的。对于需要从同一个站点抓取大量网页的程序,应该使用连接池,否则每次抓取都和Web站点建立连接、发送请求、获得响应、释放连接,一方面效率不高,另一方面稍不小心就会疏忽了某些资源的释放、导致站点拒绝连接(很多站点会拒绝同一个ip的大量连接、防止DOS攻击)。

连接池的例程如下:

[java] view plain copy

  1. SchemeRegistry schemeRegistry = new SchemeRegistry();
  2. schemeRegistry.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
  3. schemeRegistry.register(new Scheme("https", 443, SSLSocketFactory.getSocketFactory()));
  4. PoolingClientConnectionManager cm = new PoolingClientConnectionManager(schemeRegistry);
  5. cm.setMaxTotal(200);
  6. cm.setDefaultMaxPerRoute(2);
  7. HttpHost googleResearch = new HttpHost("research.google.com", 80);
  8. HttpHost wikipediaEn = new HttpHost("en.wikipedia.org", 80);
  9. cm.setMaxPerRoute(new HttpRoute(googleResearch), 30);
  10. cm.setMaxPerRoute(new HttpRoute(wikipediaEn), 50);

SchemaRegistry的作用是注册协议的默认端口号。PoolingClientConnectionManager是池化连接管理器,即连接池,setMaxTotal设置连接池的最大连接数,setDefaultMaxPerRoute设置每个路由(http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d5e467)上的默认连接个数,setMaxPerRoute则单独为某个站点设置最大连接个数。

从连接池中获取http client也很方面:

[java] view plain copy

  1. DefaultHttpClient client = new DefaultHttpClient(cm);

2、设置HttpClient参数

HttpClient需要设置合适的参数,才能更好地工作。默认的参数能够应付少量的抓取工作,但找到一组合适的参数往往能改善特定情况下的抓取效果。设置参数的例程如下:

[java] view plain copy

  1. DefaultHttpClient client = new DefaultHttpClient(cm);
  2. Integer socketTimeout = 10000;
  3. Integer connectionTimeout = 10000;
  4. final int retryTime = 3;
  5. client.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, socketTimeout);
  6. client.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, connectionTimeout);
  7. client.getParams().setParameter(CoreConnectionPNames.TCP_NODELAY, false);
  8. client.getParams().setParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 1024 * 1024);
  9. HttpRequestRetryHandler myRetryHandler = new HttpRequestRetryHandler()
  10. {
  11. @Override
  12. public boolean retryRequest(IOException exception, int executionCount, HttpContext context)
  13. {
  14. if (executionCount >= retryTime)
  15. {
  16. // Do not retry if over max retry count
  17. return false;
  18. }
  19. if (exception instanceof InterruptedIOException)
  20. {
  21. // Timeout
  22. return false;
  23. }
  24. if (exception instanceof UnknownHostException)
  25. {
  26. // Unknown host
  27. return false;
  28. }
  29. if (exception instanceof ConnectException)
  30. {
  31. // Connection refused
  32. return false;
  33. }
  34. if (exception instanceof SSLException)
  35. {
  36. // SSL handshake exception
  37. return false;
  38. }
  39. HttpRequest request = (HttpRequest) context.getAttribute(ExecutionContext.HTTP_REQUEST);
  40. boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
  41. if (idempotent)
  42. {
  43. // Retry if the request is considered idempotent
  44. return true;
  45. }
  46. return false;
  47. }
  48. };
  49. client.setHttpRequestRetryHandler(myRetryHandler);

5、6行分别设置了Socket最大等待时间、连接最大等待时间(单位都是毫秒)。socket等待时间是指从站点下载页面和数据时,两个数据包之间的最大时间间隔,超过这个时间间隔,httpclient就认为连接出了故障。连接最大等待时间则是指和站点建立连接时的最大等待时间,超过这个时间站点不给回应,则认为站点无法连接。第7行设置httpclient不使用NoDelay策略。如果启用了NoDelay策略,httpclient和站点之间传输数据时将会尽可能及时地将发送缓冲区中的数据发送出去、而不考虑网络带宽的利用率,这个策略适合对实时性要求高的场景。而禁用了这个策略之后,数据传输会采用Nagle‘s algorithm发送数据,该算法会充分顾及带宽的利用率,而不是数据传输的实时性。第8行设置socket缓冲区的大小(单位为字节),默认是8KB。

HttpRequestRetryHandler是负责处理请求重试的接口。在该接口的内部类中实现RetryRequest方法即可。当httpclient发送请求之后出现异常时,就会调用这个方法。在该方法中根据已执行请求的次数、请求内容、异常信息判断是否继续重试,若继续重试返回true,否则返回false。

3、设置request header

设置request header也是很重要的,比如设置User-Agent可以将抓取程序伪装成浏览器,骗过一些网站对爬虫的检查,设置Accept-Encoding为gzip可以建议站点以压缩格式传输数据、节省带宽等等。例程如下:

[java] view plain copy

  1. HttpResponse response = null;
  2. HttpGet get = new HttpGet(url);
  3. get.addHeader("Accept", "text/html");
  4. get.addHeader("Accept-Charset", "utf-8");
  5. get.addHeader("Accept-Encoding", "gzip");
  6. get.addHeader("Accept-Language", "en-US,en");
  7. get.addHeader("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.160 Safari/537.22");
  8. response = client.execute(get);
  9. HttpEntity entity = response.getEntity();
  10. Header header = entity.getContentEncoding();
  11. if (header != null)
  12. {
  13. HeaderElement[] codecs = header.getElements();
  14. for (int i = 0; i < codecs.length; i++)
  15. {
  16. if (codecs[i].getName().equalsIgnoreCase("gzip"))
  17. {
  18. response.setEntity(new GzipDecompressingEntity(entity));
  19. }
  20. }
  21. }
  22. return response;

各个header的含义参考http://kb.cnblogs.com/page/92320/

需要的都设上就好了。如果需要很多不同的User-Agent轮流使用(同一个User-Agent对一个站点频繁访问容易被识别为爬虫而杯具),可以去网上找,也可以在自己的chrome浏览器里看或者用抓包软件抓。值得注意的是设置了Accept-Encoding为gzip之后,对站点回复的内容要检查是否是压缩格式的,如果是,则解压缩,如上面例程中第9行之后的代码所示。

[引用请注明出处http://blog.csdn.net/bhq2010/article/details/9210007]

时间: 2024-10-29 19:11:51

Java HttpClient使用小结的相关文章

java对象序列化小结

百度百科上介绍序列化是这样的: 序列化 (Serialization): 将对象的状态信息转换为可以存储或传输的形式的过程.在序列化期间,对象将其当前状态写入到临时或持久性存储区.以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象. 序列化使其他代码可以查看或修改那些不序列化便无法访问的对象实例数据.确切地说,代码执行序列化需要特殊的权限:即指定了 SerializationFormatter 标志的 SecurityPermission.在默认策略下,通过 Internet 下载

SAE Java相关问题小结

转自:http://blog.csdn.net/bhq2010/article/details/8580412 Sae中使用的servlet容器是jetty7.4.x 我想在web.xml中配置一个自己编写的servlet,实现web启动时的初始化工作,但是总是出现各种问题,下面总结了一下在sae中使用java的一些注意事项: 1.在eclipse中开发java web项目时,我总喜欢直接把需要的jar包复制到WEB-INF/lib下,但在开发sae项目时,最好把需要的jar包放到usr lib

java单向加密算法小结(1)--Base64算法

java单向加密算法小结(1)--Base64算法 从这一篇起整理一下常见的加密算法以及在java中使用的demo,首先从最简单的开始. 简单了解 Base64严格来说并不是一种加密算法,而是一种编码/解码的实现方式. 我们都知道,数据在计算机网络之间是使用字节流的方式进行传递的,所有的信息都要最终转换为0101的二进制,这本身就涉及到编码,解码的应用. Base64,顾名思义,是使用了64个基本的字符来对任意数据进行编码的一种实现方式,那既然有Base64,是不是也有Base32,Base16

java集合框架小结(进阶版)之HashMap篇

基本概念: Hash(哈希):hash一般也译作“散列”.事实上,就是一个函数,用于直接定址.将数据元素的关键字key作为变量,通过哈希函数,计算生成该元素的存储地址. 冲突:函数是可以多对一的.即:多个自变量可以映射到同一函数值.一般而言,不同的key的hash值是不同的.在往hash表中映射的时候,不同的hash值可能映射到同一存储地址,这种情况被称为冲突. 解决冲突的方法: 1. 链表法:将冲突的各个元素用一个一维数组来维护.(java源码实现) 2. 开发寻址法:具体的有线性探测法.二次

java集合框架小结(进阶版)之HashSet篇

建议先看下:java集合框架小结(进阶版)之HashMap篇 基本概念: hashSet: 根据java集合框架小结(初级版)图示,HashSet是AbstractSet的一个子类,是基于Hash算法的Set接口的实现,顾名思义.允许添加null. --------------------------------------↑ 以上都是扯淡 ↑,↓ HashSet完全是在挂羊头卖狗肉 ↓------------------------------------------- 何谓挂羊头卖狗肉?大家

Java HttpClient

HttpClient 是 Apache Jakarta Common 下的子项目,可以用来提供高效的.最新的.功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议. http://hc.apache.org/httpcomponents-client-ga/index.html 版本:httpclient-4.2.jar 1.基本请求 //创建一个客户端 HttpClient client = new DefaultHttpClient(); //创建一个

JAVA基础—泛型小结

概念: 泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数.这种参数类型可以用在类.接口和方法的创建中,分别称为泛型类.泛型接口.泛型方法. Java语言引入泛型的好处是安全简单. 泛型的常用字符代表意思: ? 表示不确定的java类型. T  表示java类型. K V 分别代表java键值中的Key Value. E 代表Element. 下面转载于cnblog上一个写的很好的例子 真的很好,我写了半天,当看到他这个后,立即删除~ 普通泛型

JAVA: httpclient 详解;

相对于httpurlconnection ,httpclient更加丰富,也更加强大,其中apache有两个项目都是httpclient,一个是commonts包下的,这个是通用的,更专业的是org.apache.http.包下的,所以我一般用后者: httpclient可以处理长连接,保存会话,重连接,以及请求过滤器,连接重用等等... 下面是测试代码(全部总结来自官方文档,以及翻译) 须要下载核心包:httpclient-4.3.4.jar ,也可在官网下载:http://hc.apache

java集合框架小结(初级版)

今天大概的整理了一下java集合框架,在这里做一个小结,方便以后查阅,本博文主要参考资料为<java编程思想第四版>第11章——持有对象以及JAVA 1.6 API文档.并没有研究更深入的第17章<容器深入研究>.大概介绍了集合框架中几个比较常用的集合类. 以下为正文. 首先来看一张图,不太会用visio,画的可能不太好看 图中将接口.抽象类.实现类.淘汰类(圆角矩形)进行标注.有直线连接的类(或接口)表示是子类关系或者实现关系 由图示可以看出,集合类主要有两个集合接口: 1.Co