構建一個給爬蟲使用的代理IP池
做網路爬蟲時,一般對代理IP的需求量比較大。因為在爬取網站資訊的過程中,很多網站做了反爬蟲策略,可能會對每個IP做頻次控制。這樣我們在爬取網站時就需要很多代理IP。
代理IP的獲取,可以從以下幾個途徑得到:
從免費的網站上獲取,質量很低,能用的IP極少
購買收費的代理服務,質量高很多
自己搭建代理伺服器,穩定,但需要大量的伺服器資源。
本文的代理IP池是通過爬蟲事先從多個免費網站上獲取代理IP之後,再做檢查判斷IP是否可用,可用的話就存放到MongoDB中,最後展示到前端的頁面上。
獲取可用Proxy
獲取代理的核心程式碼是ProxyManager,它採用RxJava2來實現,主要做了以下幾件事:
第一,建立ParallelFlowable,針對每一個提供免費代理IP的頁面並行地抓取。對於不瞭解ParallelFlowable的同學,可以看我之前的文章
Flowable.fromIterable(ProxyPool.proxyMap.keySet())
.parallel()
第二,針對每一個頁面進行抓取,返回List
map(newFunction<String,List<Proxy>>(){
@Override
publicList<Proxy> apply(String s)throwsException{
try{
returnnewProxyPageCallable(s).call();
}catch(Exception e){
e
.printStackTrace();
}
returnnull;
}
})
第三,對每一個頁面獲取的代理IP列表進行校驗,判斷是否可用
flatMap(newFunction<List<Proxy>,Publisher<Proxy>>(){
@Override
publicPublisher<Proxy> apply(List<Proxy> proxies)throwsException{
if(proxies ==null)returnnull;
List<Proxy> result = proxies
.stream()
.parallel
()
.filter(newPredicate<Proxy>(){
@Override
publicboolean test(Proxy proxy){
HttpHost httpHost =newHttpHost(proxy.getIp(), proxy.getPort(), proxy.getType());
returnHttpManager.get().checkProxy(httpHost);
}
}).collect(Collectors.toList());
returnFlowable.fromIterable(result);
}
})
第四,依次儲存到proxyList
subscribe(newConsumer<Proxy>(){
@Override
publicvoid accept(Proxy proxy)throwsException{
log.debug("Result Proxy = "+proxy.getType()+"://"+proxy.getIp()+":"+proxy.getPort());
proxy.setLastSuccessfulTime(newDate().getTime());
ProxyPool.proxyList.add(proxy);
}
});
附上完整的流程圖