构建一个给爬虫使用的代理IP池
做网络爬虫时,一般对代理IP的需求量比较大。因为在爬取网站信息的过程中,很多网站做了反爬虫策略,可能会对每个IP做频次控制。这样我们在爬取网站时就需要很多代理IP。
代理IP的获取,可以从以下几个途径得到:
- 从免费的网站上获取,质量很低,能用的IP极少
- 购买收费的代理服务,质量高很多
- 自己搭建代理服务器,稳定,但需要大量的服务器资源。
本文的代理IP池是通过爬虫事先从多个免费网站上获取代理IP之后,再做检查判断IP是否可用,可用的话就存放到MongoDB中,最后展示到前端的页面上。
获取可用Proxy
获取代理的核心代码是ProxyManager,它采用RxJava2来实现,主要做了以下几件事:
- 创建ParallelFlowable,针对每一个提供免费代理IP的页面并行地抓取。对于不了解ParallelFlowable的同学,可以看我之前的文章RxJava 之 ParallelFlowable
Flowable.fromIterable(ProxyPool.proxyMap.keySet()).parallel()复制代码
针对每一个页面进行抓取,返回List
map(new Function<String, List<Proxy>>() {@Overridepublic List<Proxy> apply(String s) throws Exception {try {return new ProxyPageCallable(s).call();} catch (Exception e) {e.printStackTrace();}return null;}})复制代码
对每一个页面获取的代理IP列表进行校验,判断是否可用
flatMap(new Function<List<Proxy>, Publisher<Proxy>>() {@Overridepublic Publisher<Proxy> apply(List<Proxy> proxies) throws Exception {if (proxies == null) return null;List<Proxy> result = proxies.stream().parallel().filter(new Predicate<Proxy>() {@Overridepublic boolean test(Proxy proxy) {HttpHost httpHost = new HttpHost(proxy.getIp(), proxy.getPort(), proxy.getType());return HttpManager.get().checkProxy(httpHost);}}).collect(Collectors.toList());return Flowable.fromIterable(result);}})复制代码
依次保存到proxyList
subscribe(new Consumer<Proxy>() {@Overridepublic void accept(Proxy proxy) throws Exception {log.debug("Result Proxy = "+proxy.getType()+"://"+proxy.getIp()+":"+proxy.getPort());proxy.setLastSuccessfulTime(new Date().getTime());ProxyPool.proxyList.add(proxy);}});复制代码
附上完整的流程图
再附上完整的ProxyManager代码:
import com.cv4j.proxy.domain.Proxy;
import com.cv4j.proxy.http.HttpManager;
import com.cv4j.proxy.task.ProxyPageCallable;
import io.reactivex.Flowable;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpHost;
import org.reactivestreams.Publisher;
import org.springframework.stereotype.Component;import java.util.Date;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;/*** Created by tony on 2017/10/25.*/
@Slf4j
@Component
public class ProxyManager {/*** 抓取代理,成功的代理存放到ProxyPool中*/public void start() {Flowable.fromIterable(ProxyPool.proxyMap.keySet()).parallel().map(new Function<String, List<Proxy>>() {@Overridepublic List<Proxy> apply(String s) throws Exception {try {return new ProxyPageCallable(s).call();} catch (Exception e) {e.printStackTrace();}return null;}}).flatMap(new Function<List<Proxy>, Publisher<Proxy>>() {@Overridepublic Publisher<Proxy> apply(List<Proxy> proxies) throws Exception {if (proxies == null) return null;List<Proxy> result = proxies.stream().parallel().filter(new Predicate<Proxy>() {@Overridepublic boolean test(Proxy proxy) {HttpHost httpHost = new HttpHost(proxy.getIp(), proxy.getPort(), proxy.getType());return HttpManager.get().checkProxy(httpHost);}}).collect(Collectors.toList());return Flowable.fromIterable(result);}}).sequential().subscribe(new Consumer<Proxy>() {@Overridepublic void accept(Proxy proxy) throws Exception {log.debug("Result Proxy = "+proxy.getType()+"://"+proxy.getIp()+":"+proxy.getPort());proxy.setLastSuccessfulTime(new Date().getTime());ProxyPool.proxyList.add(proxy);}});}
}复制代码
定时任务
每隔几个小时跑一次定时任务,在抓取完任务之后先删除旧的数据,然后再把新的数据插入到MongoDB中。
import com.cv4j.proxy.ProxyManager;
import com.cv4j.proxy.ProxyPool;
import com.cv4j.proxy.dao.ProxyDao;
import com.cv4j.proxy.domain.Proxy;
import com.safframework.tony.common.utils.Preconditions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;import java.util.concurrent.CopyOnWriteArrayList;/*** Created by tony on 2017/11/22.*/
@Component
public class ScheduleJobs {@AutowiredProxyDao proxyDao;@AutowiredProxyManager proxyManager;/*** 每六个小时跑一次任务*/@Scheduled(cron = "0 0 */6 * * ?")public void cronJob() {System.out.println("Job Start...");proxyManager.start();CopyOnWriteArrayList<Proxy> list = ProxyPool.proxyList;// 先删除旧的数据proxyDao.deleteAll();// 然后再进行插入新的proxyif (Preconditions.isNotBlank(list)) {for (Proxy p:list) {proxyDao.saveProxy(p);}}System.out.println("Job End...");}
}复制代码
展示到前端
整个项目使用Spring Boot搭建,运行起来之后本地访问地址:
http://localhost:8080/load?pagename=proxy_list
预览效果如下:
在使用前,还可以再做一次检测,只要双击某个代理IP即可。
在第二次检测时,对于已经失效的IP会被ProxyPool删除。
总结
在做爬虫时,自己维护一个可用的代理IP池是很有必要的事情,当然想要追求更高稳定性的代理IP还是考虑购买比较好。
最后,附上github地址:
github.com/fengzhizi71…
构建一个给爬虫使用的代理IP池相关推荐
- 爬虫单个ip代理设置_爬虫怎么设置代理ip池?
网络技术现在是如此发达,用户换ip再也不用自己手动来,很多ip代理都是傻瓜式操作,智能完成切换,完全不用使用者操心. 像在我们在利用网络爬虫开展数据采集,遇到爬取频率过高.频次过多的问题,会碰到ip被 ...
- 【python】爬虫入门:代理IP池的使用、文件的写入与网易云爬取时的注意事项
一.概述 在两天前实现利用爬虫爬取网易云音乐用户的各类公开信息之后,我对现有爬虫进行了功能上的增加.主要有: ①.使用代理IP池防止IP被封: ②.将爬取用户的听歌记录.歌单.关注.粉丝这四类数据的代 ...
- 爬虫单个ip代理设置_爬虫怎样设置代理ip池
在网络迅速发展的今天,互联网企业层出不穷,爬虫工作者也越来越多,大家都知道,代理ip是爬虫工作者的一个有力助手,今天小编在这里就与大家分享一下如何设置代理池以及伪装成浏览器的方法,请看下面的介绍. 1 ...
- 爬虫--验证码,代理IP池
思路一:Cookie 登录(最简单最方便) cooke 都会保持较长的一段时间,避免因用户频繁输入账号和密码造成的不便.我们可以利用这个特性, 当我们登录成功一次之后,可以将 cooke 信息保存到本 ...
- Python3网络爬虫(十一):爬虫黑科技之让你的爬虫程序更像人类用户的行为(代理IP池等)
转载请注明作者和出处:http://blog.csdn.net/c406495762 运行平台: Windows Python版本: Python3.x IDE: Sublime text3 前言 黑 ...
- NodeJs从零构建代理ip池(一)介绍
<原文地址> 本系列主要讲解如何从零实现一个简单的代理 IP 池,教你从 Node 爬虫入门到融会贯通. 跟着本系列教程,将会学到一个完整 NodeJs 项目的开发到部署的一整套流程. 零 ...
- 爬虫采集自己构建代理ip池有什么优势?
为何一些爬虫采集的专业技术人员购买了代理ip还会继续自己构建一个ip池,自己构建ip池有什么优势? (1)可无限制的调用API获取代理ip; 购买收费的代理ip,绝大多数都会提供API链接接口,客户利 ...
- [爬虫架构] 如何在分布式爬虫架构中动态维护一个代理IP池(付费代理)
前言: 当分布式爬虫使用代理IP技术时,通过直接在爬虫程序中添加平台api接口的方式已经不能满足我们了,因为分布式的爬虫架构每秒的代理IP-URL的请求数会远远大于平台限制的请求频率,当然,对于没有限 ...
- 搭建一个自己的百万级爬虫代理ip池.
做爬虫抓取时,我们经常会碰到网站针对IP地址封锁的反爬虫策略.但只要有大量可用的代理IP资源,问题自然迎刃而解. 以前尝试过自己抓取网络上免费代理IP来搭建代理池,可免费IP质量参差不齐,不仅资源少. ...
最新文章
- pu learning的建模实践,半监督学习的好方法!
- 工业交换机的背板带宽是怎么计算的?
- 【计蒜客 - 蓝桥训练】欧拉函数(数学,数论,模板)
- livechart 只显示 y 值_【科研工具51】谷歌,谷歌学术,Scihub有效网址检索软件——Y学术...
- VB为MSHFlexGrid添加表格编辑功能
- UE4材质是什么样的机制
- com组件 的劫持_2345.com/365j.com的IE首页劫持手动修复方法+修复工具
- VMware Cloud Director 10.4 发布 (含下载) - 云计算调配和管理平台
- 【408考研笔记】操作系统完整知识点
- 猫途鹰:中国游客旅行花费低于全球平均水平,购物消费则远超全球
- STM32入门开发: 介绍SPI总线、读写W25Q64(FLASH)(硬件+模拟时序)
- Unity模拟科学计算器
- 不会比这更详细的前端工程化的入门教程了
- 使用网络监视器(IRSI)捕捉和分析协议数据包
- Meatycake,51nod2117,树状数组
- 计算机专业参赛口号,参赛口号
- 【读书笔记】天生不聪明
- 定义一个图形抽象类,完成三角形、圆形、矩形的周长和面积计算
- 【Unity3D】图片纹理压缩方式,干货走起!
- 常用软件列表,根据网上的一位仁兄稍加整理所得。再此感谢那位仁兄。