所有写搜索的朋友估计都有过和我一样的烦恼,那就是如果不断的对某一个网站进行爬行,很容易被封IP。最笨的版本就是减少爬行频率,但是在很多场景下对爬行效率是有要求的,那么最直接的办法就是不断切换实际访问的IP,来达到访问流量分散的效果。当然也有很多朋友在用一个比较贱的办法,就是用ADSL拨号方式爬行,一旦被封掉就重新拨号换个IP,这个也算一个非常取巧的手段了。

    本文重点介绍代理IP自动切换的方式,其实这个如果只是要实现,那是再简单不过了。一个爬虫在启动的时候读取一批代理IP,访问网页的时候不断轮换,这样就是一个最简单的实现。但是这样有一个比较大的问题,就是你每写一个爬虫就要实现这样的模块,多个爬虫之前还不能共享代理IP资源。

    这里我想到利用一个本地代理来实现这个效果,那么爬虫只要连接到这一个代理,他在帮忙访问最终页面的时候再使用一个代理池不断轮换。这个方案既解决了代码重复的问题,又解决了多个爬虫都要维护代理IP列表的麻烦,而且部署起来也非常简单。

    经过本方案改造前后的部署示意图:

    我这里用Jetty7的proxy server做了一个简单的例子,实现了本地代理的功能,代码非常简单,贴出来大家一起学习下吧。

 

 

 
    
 
    
  1. public class WiseProxyServlet extends ProxyServlet { 
  2.      
  3.      public void service(ServletRequest req, ServletResponse res)  
  4.         throws ServletException, IOException { 
  5.          _client.setProxy(getProperAddress()); 
  6.          super.service(req, res); 
  7.      } 
  8.  
  9.      /** 
  10.       * 这应该是在一个代理池中按照一定的规则来不断切换代理 
  11.       */ 
  12.     private Address getProperAddress() { 
  13.         return new Address("222.169.11.102"8080); 
  14.     } 
  15.       
  16.  

 

 
    
  1. public class WiseProxyServer {       
  2.        
  3.     public static void main(String[] args) throws Exception {       
  4.         Server server = new Server();       
  5.         SelectChannelConnector connector = new SelectChannelConnector();       
  6.         connector.setPort(8888);       
  7.         server.addConnector(connector);       
  8.                
  9.         HandlerCollection handlers = new HandlerCollection();       
  10.         server.setHandler(handlers);       
  11.        
  12.         // Setup proxy servlet       
  13.         ServletContextHandler context = new ServletContextHandler(handlers, "/", ServletContextHandler.SESSIONS);       
  14.         ServletHolder proxyServlet = new ServletHolder(WiseProxyServlet.class);       
  15.         context.addServlet(proxyServlet, "/*");       
  16.        
  17.         // Setup proxy handler to handle CONNECT methods       
  18.         ConnectHandler proxy = new ConnectHandler();       
  19.         handlers.addHandler(proxy);       
  20.        
  21.         server.start();       
  22.     }       
  23.        
  24. }