【解决方案】IP代理池设计与解决方案

一、背景

爬虫服务请求量大,为了应对反爬措施,增加爬虫的爬取效率和代理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中,选择一个。

posted @ 2019-05-13 18:03  清泉白石  阅读(1910)  评论(0编辑  收藏  举报