项目中一直在使用HttpClient,版本是3.6的,负责维护的同事离职后,就没有更新过,在这次项目改版中决定对这块进行升级到4.3版本,查阅了一些资料写了部分出来,还不是很完善,后期有时间在更新
这里对httpclient如何获取原页面编码进行了一些处理,感觉还不是很完善,后期想到在处理吧
具体的理论东西就不说了,代码中注释都有一些说明。
直接上代码
- /**
- * 项目名:Crawler
- * 文件名:NewsInfoLoad.java
- * 作者:zhouyh
- * 时间:2014-9-4 上午08:47:06
- * 描述:TODO(用一句话描述该文件做什么)
- */
- package com.newsTest.infoload;
- import java.io.IOException;
- import java.io.InputStream;
- import java.nio.charset.Charset;
- import java.util.regex.Matcher;
- import java.util.regex.Pattern;
- import org.apache.commons.io.IOUtils;
- import org.apache.commons.lang3.StringUtils;
- import org.apache.http.HttpEntity;
- import org.apache.http.client.ClientProtocolException;
- 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.entity.ContentType;
- import org.apache.http.impl.client.CloseableHttpClient;
- import org.apache.http.impl.client.HttpClients;
- import org.apache.http.impl.client.LaxRedirectStrategy;
- import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
- import org.apache.http.util.EntityUtils;
- import org.jsoup.Jsoup;
- import org.jsoup.nodes.Document;
- import org.jsoup.nodes.Element;
- import org.jsoup.select.Elements;
- import com.newsTest.constant.NewsConstant;
- /**
- * 类名: NewsInfoLoad
- * 包名: com.newsTest.infoload
- * 作者: zhouyh
- * 时间: 2014-9-4 上午08:47:06
- * 描述: 新闻下载类
- */
- public class NewsInfoLoad {
- //创建httpclient实例
- private CloseableHttpClient httpClient = null;
- /**
- *
- * 私有的构造函数
- * 作者:zhouyh
- */
- private NewsInfoLoad(){
- initHttpClient();
- }
- /**
- *
- * 方法名:initHttpClient
- * 作者:zhouyh
- * 创建时间:2014-9-4 上午08:53:19
- * 描述:创建httpClient连接池,并初始化httpclient
- */
- private void initHttpClient(){
- //创建httpclient连接池
- PoolingHttpClientConnectionManager httpClientConnectionManager = new PoolingHttpClientConnectionManager();
- httpClientConnectionManager.setMaxTotal(NewsConstant.MAX_TOTAL); //设置连接池线程最大数量
- httpClientConnectionManager.setDefaultMaxPerRoute(NewsConstant.MAX_ROUTE_TOTAL); //设置单个路由最大的连接线程数量
- //创建http request的配置信息
- RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(NewsConstant.REQUEST_TIMEOUT)
- .setSocketTimeout(NewsConstant.REQUEST_SOCKET_TIME).build();
- //设置重定向策略
- LaxRedirectStrategy redirectStrategy = new LaxRedirectStrategy();
- //初始化httpclient客户端
- httpClient = HttpClients.custom().setConnectionManager(httpClientConnectionManager)
- .setDefaultRequestConfig(requestConfig).setUserAgent(NewsConstant.USER_AGENT).setRedirectStrategy(redirectStrategy).build();
- }
- /********单例模式声明开始********************/
- //类初始化时,自行实例化,饿汉式单例模式
- private static final NewsInfoLoad newsInfoLoad = new NewsInfoLoad();
- /**
- *
- * 方法名:getNewsInfoLoadInstance
- * 作者:zhouyh
- * 创建时间:2014-9-4 上午08:52:19
- * 描述:单例的静态方法
- * @return
- */
- public static NewsInfoLoad getNewsInfoLoadInstance(){
- return newsInfoLoad;
- }
- /************************单例模式声明结束********/
- /**
- *
- * 方法名:loadSrc
- * 作者:zhouyh
- * 创建时间:2014-9-4 上午09:04:40
- * 描述:根据给定的url下载信息
- * @param url
- * @return
- */
- public String loadSrc(String url){
- String src = "";
- if(null==url || "".equals(url)) {
- return src; //如果url为空或者null,则返回src空值
- }
- //创建httpclient请求方式
- HttpGet httpGet = new HttpGet(url);
- CloseableHttpResponse response = null;
- try {
- //执行请求
- response = httpClient.execute(httpGet);
- //获得响应的消息实体
- HttpEntity entity = response.getEntity();
- //获取响应状态码
- int statusCode = response.getStatusLine().getStatusCode();
- //根据响应状态码进行处理
- switch (statusCode) {
- case NewsConstant.RESPONSE_200:
- //请求返回成功
- /**
- * inputstream转换成byte数组,然后将这个byte数组转成字符串(随便哪种编码方式)
- * 然后解析字符串中的编码方式。再利用这种编码方式将之前的byte数组转成正确的网页字符串
- */
- InputStream inputStream = entity.getContent();
- byte[] contentBytes = IOUtils.toByteArray(inputStream);
- src = new String(contentBytes, "gb2312");
- //获得响应字符集编码
- ContentType contentType = ContentType.getOrDefault(entity);
- String charSet = null;
- try {
- Charset charset = contentType.getCharset();
- if(charset != null){
- charSet = charset.toString();
- }
- } catch (Exception e) {
- // TODO: handle exception
- e.printStackTrace();
- }
- //如果没有获取到字符编码则从meta标签中获取
- if(charSet==null || charSet.equals("")){
- //判断页面的编码方式
- Document document = Jsoup.parse(src);
- Elements elements = document.select("meta");
- for(Element metaElement : elements){
- if(metaElement!=null && StringUtils.isNotBlank(metaElement.attr("http-equiv")) && metaElement.attr("http-equiv").toLowerCase().equals("content-type")){
- String content = metaElement.attr("content");
- charSet = getCharSet(content);
- break;
- }
- }
- }
- //用获取的编码对contentBytes进行重新编码
- if(!charSet.equalsIgnoreCase("gb2312")){
- src = new String(contentBytes, charSet);
- }
- //去除特殊标签
- src = replaceStr(src);
- break;
- default:
- break;
- }
- //关闭httpEntity流
- EntityUtils.consume(entity);
- } catch (ClientProtocolException e) {
- // TODO 这里写异常处理的代码
- e.printStackTrace();
- } catch (IOException e) {
- // TODO 这里写异常处理的代码
- e.printStackTrace();
- } finally{
- if(null != response){
- try {
- //关闭response
- response.close();
- } catch (IOException e) {
- // TODO 这里写异常处理的代码
- e.printStackTrace();
- }
- }
- }
- return src;
- }
- /**
- *
- * 方法名:getCharSet
- * 作者:zhouyh
- * 创建时间:2014-9-4 上午09:57:58
- * 描述:根据正则获取正文编码方式
- * @param content
- * @return
- */
- private String getCharSet(String content){
- String regex = ".*charset=([^;]*).*";
- Pattern pattern = Pattern.compile(regex);
- Matcher matcher = pattern.matcher(content);
- if(matcher.find())
- return matcher.group(1);
- else
- return null;
- }
- /**
- *
- * 方法名:replaceStr
- * 作者:zhouyh
- * 创建时间:2014-9-4 上午09:03:53
- * 描述:去除源码中的特殊字符
- * @param src
- * @return
- */
- public String replaceStr(String src){
- if (src == null || "".equals(src)) return null;
- src = src.replaceAll("<!--", "");
- src = src.replaceAll("-->", "");
- src = src.replaceAll("<", "<");
- src = src.replaceAll(">", ">");
- src = src.replaceAll(""", "\"");
- src = src.replaceAll(" ", " ");
- src = src.replaceAll("&", "&");
- return src;
- }
- /**
- * 方法名:main
- * 作者:zhouyh
- * 创建时间:2014-9-4 上午08:47:06
- * 描述:TODO(这里用一句话描述这个方法的作用)
- * @param args
- */
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- String url = "http://blog.sina.com.cn/s/blog_5dade77b0101lpu7.html";
- NewsInfoLoad newsLoad = NewsInfoLoad.getNewsInfoLoadInstance();
- System.out.println(newsLoad.loadSrc(url));
- }
- }