当前位置:   article > 正文

网页内容获取工具 HttpClient_httpclient httpentity

httpclient httpentity

HttpClient 简介

HttpClient 是 Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。其相比于传统 JDK 自带的 URLConnection(下一篇会讲解),增加了易用性和灵活性。其功能主要是用来向服务器发送请求,并返回相关资源。在网络爬虫实战中,经常使用 HttpClient 获取网页内容,使用 jsoup 解析网页内容

HttpClient 中包含的内容较多,在本篇中主要介绍一些常用内容,相关案例程序,已上传至 Github。针对 HttpClient 中 URL 重定向处理,HttpClient 中的请求重试等内容,读者可以在以后的实战中进一步学习。

HttpClient 相关 Jar 的下载

我们首先在 MVNRepository 中搜索 HttpClient。接着,使用 Eclipse 或其他工具构建 Maven 工程,使用 Maven 工程中的 pom.xml 下载 HttpClient 相关依赖 Jar 包。本篇以最新版 HttpClient 配置为例:

  1. <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
  2. <dependency>
  3. <groupId>org.apache.httpcomponents</groupId>
  4. <artifactId>httpclient</artifactId>
  5. <version>4.5.5</version>
  6. </dependency>

配置完成,保存 pom.xml 文件后,会发现工程自动下载了 HttpClient 依赖的相关 Jar 包,如下:

1

HttpClient 的使用

get() 方法的使用

在 HttpClient 中,提供了 get() 请求 URL 的方法。作为使用者,只需提供一个执行请求对象,HttpClient 便会向目标服务器发送 GET 请求,并返回相应的响应结果,或者请求失败时会抛出异常。在本小节主要介绍几种常用的操作。

在使用 HttpClient 之前,首先要对其进行初始化操作。接着,给定一个 URL 确定需要使用的请求方法,例如 get 方法(可以通过抓包,观察请求方法),然后向服务器发送请求,服务器接收到并解析了客户端的请求信息后,返回 HTTP 响应给客户端。HTTP 响应信息包括协议版本号,状态码等。以下为一个案例程序,请求的是 W3school 上的一个网址。

  1. HttpClient client = new DefaultHttpClient(); //初始化httpclient
  2. String personalUrl = "http://www.w3school.com.cn/b.asp"; //请求的地址URL
  3. HttpGet getMethod = new HttpGet(personalUrl); // get方法请求
  4. HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1,
  5. HttpStatus.SC_OK, "OK"); //初始化HTTP响应
  6. response = client.execute(getMethod); //执行响应
  7. String status = response.getStatusLine().toString(); //响应状态
  8. int StatusCode = response.getStatusLine().getStatusCode(); //获取响应状态码
  9. ProtocolVersion protocolVersion = response.getProtocolVersion(); //协议的版本号
  10. String phrase = response.getStatusLine().getReasonPhrase(); //是否ok
  11. if(StatusCode == 200){ //状态码200表示响应成功
  12. //获取实体内容,这里为HTML内容
  13. String entity = EntityUtils.toString (response.getEntity(),"gbk");
  14. //输出实体内容
  15. System.out.println(entity);
  16. EntityUtils.consume(response.getEntity()); //消耗实体
  17. }else {
  18. //关闭HttpEntity的流实体
  19. EntityUtils.consume(response.getEntity()); //消耗实体
  20. }

这里使用 HttpClient client = new DefaultHttpClient() 进行初始化,目前该方法已有些过时,但仍然是可以用的。另外,我们也可以使用其他的初始化方式,以下提供两种:

  1. HttpClient httpClient = HttpClients.custom().build(); //初始化httpclient
  2. HttpGet httpGet = new HttpGet("http://www.w3school.com.cn/b.asp");
  3. HttpResponse httpResponse = null;//请求响应
  4. try {
  5. httpResponse = httpClient.execute(httpGet);
  6. } catch (IOException e) {
  7. e.printStackTrace();
  8. }
  9. HttpEntity httpEntity = httpResponse.getEntity();
  10. System.out.println("get code"+httpResponse.getStatusLine().getStatusCode());
  11. String entity = EntityUtils.toString(httpEntity,"gbk"); //注意这里设置编码
  12. System.out.println(entity);
  1. CloseableHttpClient httpClient = HttpClients.createDefault(); //初始化Httpclient
  2. HttpGet httpGet=new HttpGet("http://www.w3school.com.cn/b.asp");
  3. CloseableHttpResponse response = null;//请求响应
  4. try {
  5. response = httpClient.execute(httpGet);
  6. } catch (IOException e) {
  7. e.printStackTrace();
  8. }
  9. String entity = EntityUtils.toString (response.getEntity(),"gbk");
  10. System.out.println(entity);
  11. response.close();

post() 方法的使用

直接使用 post 方法类似于上小节介绍的 get 方法,只是将 HttpGet httpGet=new HttpGet(url) 改成 HttpPost httpPost=new HttpPost(url)。但在本节我将重点介绍 HTML 表单请求方面的内容。模拟表单请求在爬虫中常用来模拟登陆 Web 应用。在 HttpClient 中,提供了实体类 UrlEncodedFormEntity 以方便处理该过程,其使用方法如下:

  1. List<NameValuePair> nvps= new ArrayList<NameValuePair>();
  2. nvps.add(new BasicNameValuePair("param1", "value1"));
  3. nvps.add(new BasicNameValuePair("param2", "value2"));
  4. UrlEncodedFormEntity entity = new UrlEncodedFormEntity(nvps, Consts.UTF_8);
  5. HttpPost httppost = new HttpPost("http://localhost/handler.do");
  6. httppost.setEntity(entity);

UrlEncodedFormEntity 实例将会使用 URL encoding 来编码参数,产生以下内容:

param1=value1&param2=value2

为更好的讲解该方法的使用,本小节介绍一个使用 Post 方法模拟登陆人人网。从下图可以看出,需要输入用户名及密码完成登陆之后,才能查看人人网中的数据。

2

为分析登陆时,客户端向服务器提交什么参数,这里需要进行网络抓包。如下图:

3

基于抓包分析的结果,便可以模拟表单向后台发送请求,具体操作(完整代码已上传至 Github)如下:

  1. HttpClient httpclient = HttpClients.custom().build(); //初始化httpclient
  2. String renRenLoginURL = "http://www.renren.com/PLogin.do"; //登陆的地址
  3. HttpPost httpost = new HttpPost(renRenLoginURL); //采用post方法
  4. //建立一个NameValuePair数组,用于存储欲传送的参数
  5. List<NameValuePair> nvps = new ArrayList<NameValuePair>();
  6. nvps.add(new BasicNameValuePair("origURL","http://www.renren.com/home"));
  7. nvps.add(new BasicNameValuePair("email", "你的邮箱地址"));
  8. nvps.add(new BasicNameValuePair("password", "你的登陆密码"));
  9. HttpResponse response = null;
  10. try {
  11. //表单参数提交
  12. httpost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
  13. response = httpclient.execute(httpost);
  14. } catch (Exception e) {
  15. e.printStackTrace();
  16. return false;
  17. } finally {
  18. httpost.abort();
  19. }

通过抓包,可以看到登陆人人网需要提交一些参数,但核心的参数是用户名及密码,从上面的程序中便可发现。另外,Post 方法也常用于用户搜索内容的网络爬虫中。例如,我们需要采集京东中的搜索产品(手机),通过抓包便可以发现需要提交的参数,如下图所示:

4

Header 信息的使用

HTTP 的请求头是客户端每次向服务器发送请求时,传递的一组属性和配置信息。在前面的章节中,已经介绍了请求头的类型。在网络爬虫中,设置请求头信息的好处,便是可以模拟浏览器行为,从而起到一定的防爬功能。当然,对于一些防爬措施很差的网址也可不做设置。在本小节中,主要介绍 HttpClient 在使用的过程中,如何设置请求头。以下仍以 W3school 上的一个网址(http://www.w3school.com.cn/b.asp)为例。同样,我们首先通过抓包的方式查看请求该网站需要的请求头信息,抓包结果如下图所示:

这里写图片描述

以下为设置设置请求头的一种方式:

  1. HttpClient httpClient = HttpClients.custom().build(); //初始化httpclient
  2. HttpGet httpget = new HttpGet("http://www.w3school.com.cn/b.asp"); //使用的请求方法
  3. //请求头配置
  4. httpget.setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
  5. httpget.setHeader("Accept-Encoding", "gzip, deflate");
  6. httpget.setHeader("Accept-Language", "zh-CN,zh;q=0.9");
  7. httpget.setHeader("Cache-Control", "max-age=0");
  8. httpget.setHeader("Host", "www.w3school.com.cn");
  9. httpget.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36"); //这项内容很重要
  10. HttpResponse response = httpClient.execute(httpget); //发出get请求
  11. //获取响应状态码
  12. int code = response.getStatusLine().getStatusCode();
  13. HttpEntity httpEntity = response.getEntity(); //获取网页内容流
  14. String entity = EntityUtils.toString(httpEntity, "gbk"); //以字符串的形式(需设置编码)
  15. System.out.println(code + "\n" + entity); //输出所获得的的内容
  16. EntityUtils.consume(httpEntity); //关闭内容流

另外,也可使用另外一种方式添加头信息:

  1. List<Header> headerList = new ArrayList<Header>(); //通过集合封装头信息
  2. headerList.add(new BasicHeader(HttpHeaders.ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"));
  3. headerList.add(new BasicHeader(HttpHeaders.USER_AGENT, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36"));
  4. headerList.add(new BasicHeader(HttpHeaders.ACCEPT_ENCODING, "gzip, deflate"));
  5. headerList.add(new BasicHeader(HttpHeaders.CACHE_CONTROL, "max-age=0"));
  6. headerList.add(new BasicHeader(HttpHeaders.CONNECTION, "keep-alive"));
  7. headerList.add(new BasicHeader(HttpHeaders.ACCEPT_LANGUAGE, "zh-CN,zh;q=0.9"));
  8. headerList.add(new BasicHeader(HttpHeaders.HOST, "www.w3school.com.cn"));
  9. //构造自定义的HttpClient对象
  10. HttpClient httpClient = HttpClients.custom().setDefaultHeaders(headerList).build();
  11. HttpGet httpget = new HttpGet("http://www.w3school.com.cn/b.asp"); //使用的请求方法
  12. //获取结果
  13. HttpResponse response = httpClient.execute(httpget); //发出get请求

在实战中,为了防止网络爬虫被封,我们往往需要设置多个 User-Agent,在请求网站的多个页面时,可以自由的从这些 User-Agent 随机切换,进而达到模拟人行为的请求。

HttpClient 中的超时问题

在网络爬虫中,有时也需要设置连接超时和获取数据超时,原因是超时会影响程序的继续运行。HttpClient 中可设置三个超时:RequestTimeout(从连接池中获取连接的超时时间)、ConnectTimeout(建立连接的超时)、SocketTimeout(请求获取数据的超时时间)。其使用方式如下:

  1. //全部设置为10
  2. RequestConfig requestConfig = RequestConfig.custom()
  3. .setSocketTimeout(10000).setConnectTimeout(10000).setConnectionRequestTimeout(10000).build();
  4. //配置HttpClient
  5. CloseableHttpClient httpClient = HttpClients.custom().setDefaultRequestConfig(requestConfig).build();
  6. CloseableHttpResponse response = null;
  7. try {
  8. response = httpClient.execute(new HttpGet("http://www.w3school.com.cn/b.asp")); //使用get方法发送请求
  9. }catch (Exception e){
  10. e.printStackTrace();
  11. }
  12. String result = EntityUtils.toString(response.getEntity(),"gbk"); //获取结果,html
  13. System.out.println(result); //输出结果

另外,也可针对 HttpPost 或 HttpGet 设置超时,使用方式如下:

  1. CloseableHttpClient httpClient = HttpClients.createDefault(); //初始化httpClient
  2. HttpGet httpGet=new HttpGet("http://www.w3school.com.cn/b.asp");//Get请求(Post方法相似)
  3. RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(2000).setConnectTimeout(2000).build();//设置请求和传输超时时间
  4. httpGet.setConfig(requestConfig); //httpget信息配置
  5. CloseableHttpResponse response = null;
  6. try {
  7. response = httpClient.execute(httpGet); //使用get方法发送请求
  8. }catch (Exception e){
  9. e.printStackTrace();
  10. }
  11. String result = EntityUtils.toString(response.getEntity(),"gbk"); //获取结果,html
  12. System.out.println(result); //输出结果

代理服务器的使用

代理服务器(Proxy Server)是网上提供转接功能的服务器,一般情况下,我们使用网络浏览器直接连接其他Internet站点取得网络信息。代理服务器是介于客户端和 Web 服务器之间的另一台服务器,基于代理,浏览器不再直接向 Web 服务器取数据,而是向代理服务器发出请求,信号会先送到代理服务器,由代理服务器取回浏览器所需要的信息。简单的可以理解为中介。

在网络爬虫中,使用代理服务器访问站点内容,能够隐藏爬虫的真实 IP 地址,从而防止网络爬虫被封。另外,普通网络爬虫使用固定 IP 请求时,往往需要设置随机休息时间,而通过代理却不需要,从而提高了爬虫的效率。目前,代理可以来源于提供免费代理地址以及接口的网站(例如https://free-proxy-list.net/),但这些免费的代理 IP 都是不稳定的。另外,也可通过购买的方式使用代理,其提供的代理 IP 可用率较高,稳定性较强。在本小节中,我介绍在 HttpClient 中如何基于代理 IP 来请求网页,我仍以请求 W3school 的网址为例:

  1. RequestConfig defaultRequestConfig = RequestConfig.custom()
  2. .setProxy(new HttpHost("171.97.67.160", 3128, null))
  3. .build(); //添加代理
  4. HttpGet httpGet = new HttpGet("http://www.w3school.com.cn/b.asp"); //设置请求的方式及网页
  5. HttpClient httpClient = HttpClients.custom().
  6. setDefaultRequestConfig(defaultRequestConfig).build(); //配置httpClient
  7. HttpResponse httpResponse = httpClient.execute(httpGet); //执行请求
  8. System.out.println("状态码为:"+httpResponse.getStatusLine().getStatusCode());
  9. String result = EntityUtils.toString(httpResponse.getEntity(),"gbk"); //获取结果,html
  10. System.out.println(result); //输出结果

在程序中,代理添加包括其 IP 地址以及端口。该案例,只是使用了一个代理 IP。在实际应用中,我们往往需要使用很多的代理 IP,不断的切换去访问不同的网页。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/316711
推荐阅读
相关标签
  

闽ICP备14008679号