数据抓取之性能优化第一弹

数据抓取本身流程很简单,但是当遇到网站的种类变多或者要采集的数据变多的时候,性能问题会称为数据抓取中要首要解决的问题。
这几天同事在测试采集数据的时候总是遇到反应很慢的情况。今晚趁着洗完澡脑子清醒,针对部分问题重构了下;做下记录。

这次遇到的问题主要是代理的问题,场景是这样的:

  • 我有100个代理,
  • 系统初始化的时候,我把这100个代理中放到一个队列(ArrayBlockingQueue)中。
  • 然后平均每个采集类(一个采集类对应一个网站或者一类网站)分配10个代理。
  • 问题来了,当我网站超过10个到11个的时候,这时候启动系统,第十一个采集类会无法从代理中获取代理。于是第十一个类一直在登真队列中哪个好心人把代理资源放回来。可惜它永远登不到那天。

问题的原因其实是我多虑了,因为代理资源本身是可以多个采集类共用的。而我起初的考虑是为了让代理资源能够均衡使用,不至于某个代理频繁的被使用,而某些代理永远没有用到(浪费了)。

我的解决方法是这样的:

  • 把代理资源放在一个List中,而不是队列中。
  • 每个采集类获取代理的时候从list中顺序获取,从第1个代理获取,到100个以后,再重头开始继续依次获取。
  • 由于List中无法自己标记当前获取到第几个了,且在多线程环境下,所以使用了AtomicInteger来做计数器。
  • 参考代码如下:
    import java.io.InputStream;
    import java.util.List; 
    import java.util.concurrent.atomic.AtomicInteger;

    import org.apache.commons.io.IOUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;


    public class ProxieQueue {

        private static Logger logger = LoggerFactory.getLogger(ProxieQueue.class);
        private static List<Proxie> proxieList = com.google.common.collect.Lists.newArrayList();
        private static AtomicInteger listCounter =new AtomicInteger();
        private ProxieQueue() {

        }

        static {
            try {
                InputStream is =Configurations.class.getClassLoader().getResourceAsStream("proxies.txt");
                List<String> lineList = IOUtils.readLines(is); ;
                for (String line : lineList) {
                    String[] strArray = line.split(":");

                    Proxie proxie = new Proxie();
                    proxie.setUrl(strArray[0]);
                    proxie.setUser(strArray[1]);
                    proxie.setPass(strArray[2]);
                    proxie.setPort(Integer.valueOf(strArray[3]));
                    proxieList.add(p);
                }
            } catch (Exception e) {
                logger.error("读取代理配置失败", e);
            }


        }


        public static Proxie get() {
            int index = listCounter.getAndIncrement();
                if(index == proxieList.size()){
                   //获取到结尾后,从头开始继续获取
                   index= listCounter.getAndSet(0);
                }
                return  proxieList.get(index);       
        }
    }
  • 另外我是在系统初始化的时候就将各个网站的采集类初始化好的,这样其实没有必要,完全可以在采集这个网站的时候再进行初始化即可。

欢迎去我的个人站点查看文章
或者,欢迎关注俺的微信订阅号,每天一篇小笔记,每天提高一点点:

公众号:enilu123
这里写图片描述

猜你喜欢

转载自blog.csdn.net/mooyinn/article/details/50392088
今日推荐