专栏首页路人甲Java我们的爬虫真的这么让人讨厌么?

我们的爬虫真的这么让人讨厌么?

本文内容

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

2、webmagic中代理的使用

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

存在的问题

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

爬虫被屏蔽的原因

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

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

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

未使用代理的情况

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

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

解决办法

使用代理来解决问题

请求过程如下:

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

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

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

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

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

webmagic中使用代理

从0.7.1版本开始,WebMagic开始使用了新的代理API ProxyProvider。因为相对于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获取代理实例。

爬虫系列清单

  1. java爬虫系列第一讲-爬虫入门(爬取动作片列表)
  2. java爬虫系列第二讲-爬取你喜欢电影的下载地址
  3. java爬虫系列第三讲-获取页面中绝对路径的各种方法
  4. 带你抓取《极客时间》各种课程信息

本文分享自微信公众号 - 路人甲Java(javacode2018)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-04-23

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Spring系列第1篇:请问各位大佬为何要学spring?

    整个spring系列使用官方最新版本5.2.3.RELEASE,会有大量案例,都是通过maven来管理的,所以maven是必备技能,对这块不熟悉的可以去看一下:...

    路人甲Java
  • Spring系列第2篇:控制反转(IoC)与依赖注入(DI),晦涩难懂么?

    Spring中有3个核心的概念:控制反转(Ioc)、依赖注入(DI)、面向切面编程(AOP),spring中其他的技术都是依靠3个核心的技术建立起来的,所以玩s...

    路人甲Java
  • java高并发系列-第2天:并发级别

    这是java高并发系列第2篇文章,一个月,咱们一起啃下java高并发,欢迎留言打卡,一起坚持一个月,拿下java高并发。

    路人甲Java
  • 构建一个给爬虫使用的代理IP池总结

    做网络爬虫时,一般对代理IP的需求量比较大。因为在爬取网站信息的过程中,很多网站做了反爬虫策略,可能会对每个IP做频次控制。这样我们在爬取网站时就需要很多代理I...

    fengzhizi715
  • 关于Spring属性处理器PropertyResolver以及应用运行环境Environment的深度分析,强大的StringValueResolver使用和解析【享学Spring】

    若直接提PropertyResolver或者StringValueResolver可能很小伙伴会觉得非常的陌生,但是我若提Environment和Embedde...

    YourBatman
  • 使用Kotlin Reified 让泛型更简单安全

    我们在编程中,出于复用和高效的目的,我们使用到了泛型。但是泛型在JVM底层采取了类型擦除的实现机制,Kotlin也是这样。然后这也带来了一些问题和对应的解决方案...

    技术小黑屋
  • Oozie分布式工作流——EL表达式

    oozie支持使用EL(expression language)表达式。 基本的EL常量 KB MB GB TB PB 基本EL函数 string fir...

    用户1154259
  • 《Java从入门到放弃》框架入门篇:springMVC数据传递

    十方上下
  • Facebook开发AI模型,旨在将MRI扫描速度提高10倍

    Facebook AI Research正在与纽约大学医学院合作,通过AI将MRI扫描速度提高10倍。在fastMRI项目中使用的AI模型通过纽约大学获得的10...

    AiTechYun
  • Android 应用程序签名

    Android应用程序签名相关的理论知识包括:什么是签名、为什么要给应用程序签名、如何给应用程序签名等。

    阳光岛主

扫码关注云+社区

领取腾讯云代金券