一、背景
爬虫服务请求量大,为了应对反爬措施,增加爬虫的爬取效率和代理IP使用率,需要设计一个IP代理池,满足以下需求:
- 定时任务获取第三方代理
- 及时剔除IP代理池中失效的IP
- 业务隔离IP
- 若IP未失效,但对某个业务来说,IP被封,需要针对业务,隔离此IP
- 均衡使用IP
- 避免IP使用频率不均问题
通常选用的地上那方外部代理有:蚂蚁代理、阿布云、讯代理(不建议使用)。这里以讯代理为例。
说说讯代理
实际环境测试过,代理质量差,价格不低,客服态度不好。笔者以公司的名义提需求,价钱好商量,对方直截了当回复,没这功能,也做不了,爱买不买,呵呵。所以真心不建议使用。
1.1 调用代理API
调用混拨代理API,返回结果
{
"ERRORCODE":"0",
"RESULT":[
{"port":"43617","ip":"222.85.5.118"},
{"port":"43569","ip":"180.122.20.108"},
{"port":"20443","ip":"221.230.254.73"}
]}
二、一些知识点
2.1 代理IP是如何产生的?
ASDL拨号,是一种上网方式,每拨一次号,就会产生一个新的IP。而第三方的IP厂商,通常会买很多拨号VPS服务器,定时拨号来产生新的IP,提供给需要代理的客户。
三、需求1:及时剔除IP代理池中失效的IP
3.1 超过有效时间,自动失效
每个IP都有固定的有效时间(拨号时间)。IP失效的原理,IP通过ASDL拨号产生,当ASDL重新拨号,则旧IP失效,新IP产生。如3分钟拨一次号,或3-10分钟拨一次号,为了保证IP的使用率,通常以最长的失效时间(如有效期3-10分钟,选10分钟作为失效时间)。
使用Redis存储Key-Value,失效时间为最长有效时间。Key为IP+端口。Value为任意固定值。
3.2 检测失效
检测时间点
- 获取到IP时,放入代理池之前
- 在代理池中
通常IP的真正有效时间不是固定的,比如说的有效时间是3分钟,真实有效时间可能低于3分钟。这里就需要有一个机制来单独检测IP是否有效。
通常的做法是,IP池中的每一个IP都要定时访问一个固定的测试链接,访问失效则从队列中剔除。
如何选择固定的链接,有下列几种要求:
- 测试链接的网站要尽可能地稳定
- 返回的内容要尽可能的小
- 网站最好不要有反爬措施
测试链接
测试链接的一个比较好的方案是,自己提供一个CDN链接,链接指向一个只有200字符串的txt文本。
最好提供两个CDN链接,同时请求,只要有一个能请求通,就判断为IP有效。防止一处CDN挂掉,导致所有代理IP被判定为失效。
3.3 伪代码
获取代理时
请求API,解析获取代理列表:
每个代理:
if(isEffectiveIp(ip)){
addIpPool(ip);
}
IP代理池中检查
获取当前代理池中所有IP:
if(!isEffectiveIp(ip)){
removeIp(ip);
}
四、需求2:业务隔离IP
4.1 IP隔离判定
错误记录队列
这里IP调用服务就需要做成一个单独的服务,其他业务服务都调用该IP服务。每次调用的时候需要上报IP,IP可用或不可用,同时附带业务名(如business-1)。
IP服务端维持一个队列记录,记录业务与IP的错误次数,Key为业务名-IP,Value为错误次数,设置一个标准值,若连续错误N次,则将此IP放到失效队列。
失效队列
失效队列中,使用set存储,name为业务名称,value为失效IP
调用IP服务
业务每次调用IP,首先获取失效队列中的IP列表,然后请求时附带IP列表作为参数,请求不包含失效IP的任意IP。
五、需求3:均衡使用IP
使用zset维持,使用时间戳作为score,zset会以score从小到大排列。
当一个IP被使用,则设置score为当前时间戳,则IP会排到队尾。
每次获取IP时,都从队头的前N个IP中,选择一个。