美文网首页
Java爬虫 (五) -- httpClient进阶:使用代理(

Java爬虫 (五) -- httpClient进阶:使用代理(

作者: Richard_易 | 来源:发表于2018-03-15 12:41 被阅读0次

    一、前言

    好久没有写博客,趁着难得的空闲时间更新一波。前面几期讲到的主要包括了爬虫开发中的页面获取、页面解析两个方面的知识,套用二八原则,可以解决80%的工作。但是其他的20%的工作,就可能要用到我们80%的时间和精力去研究。这个就是我接下去几期要讲的。这期主要是讲一些实际场景下可能需要用到的httpClient设置,大都是我在实际开发中需要用到的,都算是一些小知识点,但是还是希望能能够记录总结一下。

    接下去的博文都会标注写文章时参考的资料,以便参考。(感觉跟写论文一样,2333~)

    二、代理

    代理是爬虫技术中很重要的一项。因为有一些网站会有相应的安全策略。例如检测一段时间内,某个IP地址的访问次数,如果访问频率过高,说明你不是正常访客,然后禁止你这个IP的访问。

    应对这种机制有两种手段:

    1. 放慢抓取速度,减小对目标网站的访问压力
    2. 设置代理IP,实现高频率抓取,但是这需要多个稳定的代理IP。

    代理ip资源可以自己去写爬虫去爬代理网站,去验证可用性,当然这种方式不稳定,而且可用的ip资源并不是很多。你也可以搭建自己的代理服务器。还有些爬虫每天的抓取任务可能需要消耗10多万的ip资源,这个时候一般是需要使用一些商业的代理ip商的服务了。

    当然在本文中,不会涉及如何搭建代理服务器和如何获取ip资源。主要介绍如何在httpClient中配置ip。如果以后有机会涉及到,再写文章吧。

    三、实战

    由于httpClient十分灵活,设置代理也有很多种方式。

    3.1 设置httpClient

    • 最简单的一种:
    // proxyHost -- 代理ip; proxyPort -- 端口号
    HttpHost proxy = new HttpHost("proxyHost", proxyPort, "HTTP");
    CloseableHttpClient httpclient = HttpClients.createDefault();
    HttpGet get = new HttpGet(url);
    CloseableHttpResponse response = httpclient.execute(proxy, get);
    

    这种方式要注意一点:new HttpHost()是支持指定协议类型的,但是httpClient不默认支持socks协议,所以如果我们把上面代码中的协议改成new HttpHost("proxyHost", proxyPort, "SOCKS"),会报错。

    > org.apache.http.conn.UnsupportedSchemeException: socks protocol is not supported
    

    还有两种方法是官方文档上推荐的:

    • 使用RequestConfig:
    CloseableHttpClient httpclient = HttpClients.createDefault();       
    HttpGet request = new HttpGet(url);
     
    request.setConfig(
        RequestConfig.custom()
            .setProxy(new HttpHost("proxyHost", proxyPort, "HTTP"))
            .build()
    );
             
    CloseableHttpResponse response = httpclient.execute(request);
    
    • 使用RoutePlanner
    // 1. 设置默认参数的方法
    HttpHost proxy = new HttpHost("proxyHost"proxyPort); 
    DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy); 
    CloseableHttpClient httpclient = HttpClients.custom(). 
            setRoutePlanner(routePlanner)
            .build();
    
    // 2. 使用标准的JRE代理选择器,即使用系统代理
    SystemDefaultRoutePlanner routePlanner = new SystemDefaultRoutePlanner(
            ProxySelector.getDefault());
    CloseableHttpClient httpclient = HttpClients.custom()
            .setRoutePlanner(routePlanner)
            .build();
    

    3.2 RoutePlanner

    这个类单独拿出来讲一下。在httpClient的请求执行过程中,HttpRoute首先出现在请求执行链的入口处,在进入请求执行链之前,使用routePlanner来根据目标主机、请求和请求上下文来计算出HttpRoute. 下列代码摘自InternalHttpClient类源码片段:

    @Override  
    protected CloseableHttpResponse doExecute(  
            final HttpHost target,  
            final HttpRequest request,  
            final HttpContext context) throws IOException, ClientProtocolException {  
              
        ...  
              
        <strong>final HttpRoute route = determineRoute(target, wrapper, localcontext);</strong>  
        // 开始调用请求执行链  
        return this.execChain.execute(<strong>route</strong>, wrapper, localcontext, execAware);  
          
        ...  
    }  
      
    private HttpRoute determineRoute(  
            final HttpHost target,  
            final HttpRequest request,  
            final HttpContext context) throws HttpException {  
        HttpHost host = target;  
        if (host == null) {  
            host = (HttpHost) request.getParams().getParameter(ClientPNames.DEFAULT_HOST);  
        }  
        <strong>return this.routePlanner.determineRoute(host, request, context);</strong>  
    } 
    

    HttpClient默认计算HttpRoute的算法大致为:

    • 如果在请求上下文context里能找到代理,直接用来创建HttpRoute对象;
    • 如果没有设置代理,并且没有使用系统属性,用DefaultRoutePlanner,计算出的HttpRoute的proxyChain为null;
    • 如果设置了代理,用DefaultProxyRoutePlanner,计算出的HttpRoute的proxyChain里只有一个,就是设置的代理;
    • 如果没有设置代理,但使用系统数据,用SystemDefaultRoutePlanner,它使用JDK的ProxySelector,从JVM配置和系统配置里获取代理链,再从代理链里寻找第一个HTTP类型的代理,来创建HttpRoute对象。如果没有找到HTTP类型的代理,计算出的HttpRoute的proxyChain为null.

    对应到上面我们的代理配置的几种方法可以分为两种,1.给httpClient配置代理;2.配置系统代理。

    3.3 设置系统代理

    实战中最后一种方法就是使用系统代理的方法。那么怎么设置系统代理呢?

    这里说的系统代理配置指的 JVM 系统,而不是操作系统。

    3.3.1 Java System

    可以通过下面的方式来分别设置 HTTP 代理,HTTPS 代理和 SOCKS 代理:

    // HTTP 代理,只能代理 HTTP 请求
    System.setProperty("http.proxyHost", "127.0.0.1");
    System.setProperty("http.proxyPort", "9876");
     
    // HTTPS 代理,只能代理 HTTPS 请求
    System.setProperty("https.proxyHost", "127.0.0.1");
    System.setProperty("https.proxyPort", "9876");
     
    // 同时支持代理 HTTP/HTTPS 请求
    System.setProperty("proxyHost", "127.0.0.1");
    System.setProperty("proxyPort", "9876");
    
    // SOCKS 代理,支持 HTTP 和 HTTPS 请求
    // 注意:如果设置了 SOCKS 代理就不要设 HTTP/HTTPS 代理
    System.setProperty("socksProxyHost", "127.0.0.1");
    System.setProperty("socksProxyPort", "1080");
    

    3.3.2 JVM 命令行参数

    在IDE项目启动设置中设置JVM 参数。

    如果idea的话如下:

    image

    参考资料

    1. http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d5e485
    2. http://blog.csdn.net/zjysource/article/details/52945494
    3. http://www.aneasystone.com/archives/2015/12/java-and-http-using-proxy.html

    相关文章

      网友评论

          本文标题:Java爬虫 (五) -- httpClient进阶:使用代理(

          本文链接:https://www.haomeiwen.com/subject/gsthqftx.html