zoukankan      html  css  js  c++  java
  • java爬虫系列第五讲-如何使用代理防止爬虫被屏蔽?

    本文内容

    1、分析一下爬虫存在的问题及解决方案

    2、webmagic中代理的使用

    3、目前市面上一些比较好用的代理服务器

    存在的问题

    我们在使用爬虫过程中,大多都会遇到这样的问题:突然某一天爬虫爬不到内容了,目标网站直接返回404或者其他错误信息,这说明我们的爬虫被目标网站给屏蔽了。

    爬虫被屏蔽的原因

    1、爬虫大量请求对对目标服务器造成了压力

    2、爬虫采集目标网站有价值的内容到处传播,对目标网站造成了不良影响

    出于以上原因,正常情况下目标网站会把爬虫屏蔽掉,这样直接导致我们开发的爬虫无法采集正确的内容。

    未使用代理的情况

    我们的爬虫程序以一个固定的ip去访问目标网站,目标网站会发现这个固定的ip有大量的请求,会判定为爬虫,直接进行屏蔽。

    如果我们每次请求发送的ip都不一样,这样目标网站一般情况下就不会把我们当成爬虫屏蔽了。

    解决办法

    使用代理来解决问题

    请求过程如下:

    1、爬虫采集请求给代理服务器

    2、代理服务器一般是一个集群,内部有很多机器,代理随机选择一台机器,将请求发送给目标服务器

    3、目标服务器将结果返回给代理服务器

    4、代理服务器将结果返回给爬虫

    可以看出,整个系统的稳定性在代理服务器上,代理服务器的质量直接影响到整个程序的稳定性。

    webmagic中使用代理

    从0.7.1版本开始,WebMagic开始使用了新的代理APIProxyProvider。因为相对于Site的“配置”,ProxyProvider定位更多是一个“组件”,所以代理不再从Site设置,而是由HttpClientDownloader设置。

    API 说明
    HttpClientDownloader.setProxyProvider(ProxyProvider proxyProvider) 设置代理

    ProxyProvider有一个默认实现:SimpleProxyProvider。它是一个基于简单Round-Robin的、没有失败检查的ProxyProvider。可以配置任意个候选代理,每次会按顺序挑选一个代理使用。它适合用在自己搭建的比较稳定的代理的场景。

    代理示例:

    1、设置单一的普通HTTP代理为101.101.101.101的8888端口,并设置密码为"username","password"

    HttpClientDownloader httpClientDownloader = new HttpClientDownloader();
    httpClientDownloader.setProxyProvider(SimpleProxyProvider.from(new Proxy("101.101.101.101",8888,"username","password")));
    spider.setDownloader(httpClientDownloader);
    

    2、设置代理池,其中包括101.101.101.101和102.102.102.102两个IP,没有密码

    HttpClientDownloader httpClientDownloader = new HttpClientDownloader();
            httpClientDownloader.setProxyProvider(SimpleProxyProvider.from(new Proxy("101.101.101.101", 8888), new Proxy("102.102.102.102", 8888)));
    

    免费代理服务器

    1、目前用的还不错的有快代理,有免费 和 收费版,如果是咱们自己搞着玩,可以使用免费版的,如果对代理服务器要求比较高,可以用他们的付费版的。我之前做过一个爬取财经数据的程序,对代理要求比较高,使用的是他们的收费版的,用下来还可以的。如果你们有发现更好的,可以留言,分享分享,谢谢

    对于快代理我这边提供一个代理代码,可以拿去直接用:

    public class KuaidailiProxyProvider implements ProxyProvider {
        private Logger logger = Logger.getLogger(KuaidailiProxyProvider.class);
    
        private List<Proxy> proxyList = new ArrayList<>();
        private volatile Map<String, ArrayBlockingQueue<Proxy>> siteProxysMap = new HashMap<String, ArrayBlockingQueue<Proxy>>();
        private Object siteProxysMapLock = new Object();
        //获取代理信息的地址
        private String apiurl;
        //用户名
        private String username;
        //密码
        private String password;
        private volatile static KuaidailiProxyProvider instance = null;
    
        public KuaidailiProxyProvider(String apiurl, String username, String password) {
            this.apiurl = apiurl;
            this.username = username;
            this.password = password;
            this.init();
        }
    
        public static KuaidailiProxyProvider getInstance(String apiurl, String username, String password) {
            if (instance == null) {
                synchronized (KuaidailiProxyProvider.class) {
                    if (instance == null) {
                        instance = new KuaidailiProxyProvider(apiurl, username, password);
                    }
                }
            }
            return instance;
        }
    
        private void init() {
            try {
                logger.info("get proxy");
                String s = HttpsUtil.requestGet(this.apiurl);
                logger.info(s);
                if (StringUtil.isNotEmpty(s)) {
                    final JSONObject jsonObject = JSON.parseObject(s);
                    if (jsonObject == null) {
                        return;
                    }
                    final JSONObject data = jsonObject.getJSONObject("data");
                    if (data == null) {
                        return;
                    }
                    final JSONArray proxy_list = data.getJSONArray("proxy_list");
                    if (proxy_list == null && proxy_list.size() == 0) {
                        return;
                    }
                    List<String> tempList = new ArrayList<>();
                    for (int i = 0; i < proxy_list.size(); i++) {
                        final String string = proxy_list.getString(i);
                        final String[] split = string.split(":");
                        proxyList.add(new Proxy(split[0], Integer.parseInt(split[1]), this.username, this.password));
                    }
                }
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
        }
    
        private ArrayBlockingQueue<Proxy> get(String key) {
            try {
                ArrayBlockingQueue<Proxy> queue = siteProxysMap.get(key);
                if (queue == null) {
                    synchronized (siteProxysMapLock) {
                        queue = siteProxysMap.get(key);
                        if (queue == null) {
                            ArrayBlockingQueue<Proxy> proxies = new ArrayBlockingQueue<Proxy>(proxyList.size());
                            for (Proxy proxy : proxyList) {
                                proxies.put(proxy);
                            }
                            siteProxysMap.put(key, proxies);
                        }
                    }
                }
            } catch (InterruptedException e) {
                this.logger.error(e.getMessage(), e);
            }
            return siteProxysMap.get(key);
        }
    
        @Override
        public void returnProxy(Proxy proxy, Page page, Task task) {
            this.logger.info(proxy);
            try {
                String key = getKey(task);
                this.get(key).put(proxy);
            } catch (InterruptedException e) {
                this.logger.error(e.getMessage(), e);
            }
        }
    
        private String getKey(Task task) {
            final String domain = task != null && task.getSite() != null ? task.getSite().getDomain() : null;
            return StringUtil.isNotEmpty(domain) ? domain : KuaidailiProxyProvider.class.getName();
        }
    
        @Override
        public Proxy getProxy(Task task) {
            Proxy proxy = null;
            try {
                proxy = this.get(this.getKey(task)).take();
                this.logger.info(proxy);
            } catch (InterruptedException e) {
                logger.error(e.getMessage(), e);
            }
            return proxy;
        }
    }
    

    调用KuaidailiProxyProvider.getInstance获取代理实例。

    可以关注公众号:路人甲Java,获取年薪50万课程,获取最新文章。

  • 相关阅读:
    关于 Vue
    HTTP 知识点
    JS 的一些原生属性
    JS知识点-2 通信类
    原生JS知识点
    CSS知识点
    HTML知识点
    关于在Ajax中使用pushstate
    JavaScript 中的 This
    观察者模式
  • 原文地址:https://www.cnblogs.com/itsoku123/p/10755529.html
Copyright © 2011-2022 走看看