PID控制器——控制网络爬虫速度

一、初识PID控制器

  冬天乡下人喜欢烤火取暖,常见的情形就是四人围着麻将桌,桌底放一盆碳火。有人觉得火不够大,那加点木炭吧,还不够,再加点。片刻之后,又觉得火太大,脚都快被烤熟了,那就取出一些木碳……直到火盆里的火刚刚合适。这样一个看似简单的情形中就包括PID控制系统的四个主要过程:设定目标,测量,比较和执行。结合PID控制器这四个过程来重新阐述上述情形是这样的:人烤火时所期待的最合适的温度是我们设定的目标;每个人都是一个传感器,能感知到温度的大小(虽然只是模糊的感知)——这是一个测量的过程;我们感知到的温度是不是最适合我们,是大还是小——这是一个比较的过程;比较之后,我们知道火是大还是小了,小了就加点木炭,大了就取出部分木炭——这是一个执行的过程。不断重复最后三个过程(如图1所示),直至使人能感觉到温度比较合适。

图1 PID控制过程循环

二、控制网络爬虫速度

  为什么要控制爬虫速度,难道像高铁一样快不好吗?其中有两方面原因:一、对于目标网站来说是一种礼貌,如果速度太快,将给服务器造成过大的负载;二、对于本人来说,抓取速度太快将导致致服务器禁止访问,从而丢失大量有效数据,甚至需要重新抓取。那么如何控制爬虫抓取网页的速度,使它不至于太快?

  通常情况下,在每个页面抓取之间设定较大的延时等待以限制最大访问频率,可以保证既不会给服务器造成过重负担,也不会因访问太频繁而被服务器禁止,然而这样的方法将导致网络利用率低,抓取速度慢,对于大量网页的抓取任务来说,往往是无法忍受的。

图2 网络流畅和网络较差时网页抓取时间对比

   图2是一个简化的理想模型,可以很好的说明这个问题,假设某网站允许的最大访问频率为6页/分钟,于是最小时间间隔为10s,这个时间要通过很多次重复试验来确定(网站管理员肯定不会告诉你的)。网络流畅时每个网页读取时间为0.5s,为了保证不被服务器屏蔽,至少要等待9.5s的间隔时间才继续抓取下一个页面,这个9.5s的间隔时间是固定的,即使网络较差时也要等待这么长的时间。网络较差时,网页读取时间为9.5s,再延时等待9.5s,于是每个网页的读取时间变为19s,几乎是网络流畅时的两倍。而实际上网络较差时的理想情况下,只需要等待0.5s,这时便保持和网络流畅时相同的抓取速度,由此可见这种限制最大速度的方法是很低效的。另外延时等待时间对抓取频率的影响是很模糊的,延时1s时抓取频率是100页/分钟,那么延时10s就是10页/分钟吗?很难确定,尤其是在复杂的网络环境中。

   要改进上述方法,一种很自然的解决方案就是:使等待时间动态变化,即等于最小时间间隔减去网页读取时间,这样就能保证网页平均抓取时间在网络流畅和网络较差时都为最小时间间隔。这种方法对于单线程的爬虫访问小规模网站来说也许可行,但在多线程分布式的爬虫访问大规模网站时,整体上的抓取时间由许多并行的抓取任务共同决定,并且各种异常情况(页面无效或者连接超时)使得抓取时间更加不可计算,这种方法就显得相当笨拙了。综合考虑各种因素,显然我们需要一种模糊的,不需要精确计算的方法来控制爬虫抓取速度,而且这个速度是很直观的以频率(页/分钟)来表示——PID控制算法就是其中一种。

三、PID控制爬虫速度

  PID控制器控制爬虫速度的原理简单来说就是:速度快了,增加延时时间;速度慢了,减小延时时间——是否已经看到了其中与本文开始所描述的烤火情形之间的相似性?类比烤火的情形,我设想PID控制爬虫速度的方案是:

    1)初始化:设定初始延时时间T0和比例系数Kp(典型值-0.05)

    2)目标设定:设定爬虫速度S,比如40页/分钟。

    3)测量:统计每分钟内爬虫抓取网页的数量n,可能是32,也可能是100等.

    4)比较:比较n和S的大小

    5)执行:n如果比S大,说明太快了,于是增加延时时间;n如果比S小,说明太慢了,于是减小延时时间。

  该方案的公式化表示如下,

Tk=Tk-1+Kp*(S-n)                    (3.1)              

  其中k=1, 2, 3 ... ,Tk是第k次设定的延时时间。不要被表达式吓住了,它所传达的意思其实就是5)所描述的执行过程:速度太快 (S-n小于0, Kp*(S-n)为正),增加延时 (Tk大于Tk-1);速度太慢 (S-n大于0, Kp*(S-n)为负),减小延时 (Tk小Tk-1)。

  假设初始延时时间T0为1.0s, 比例系数Kp为-0.05,爬虫速度S设置为40页/分钟。如果某次爬虫抓取网页的数量n=100,根据3.1式计算的延时值为T1=T0+Kp*(S-n)=1.0+(-0.05)*(40-100)=4.0。下一次可能的测量值n=30,则计算的延时值T2=4.0-0.05*10=3.5。

图3 PID控制曲线

  图3是某次试验中PID控制曲线,下面的数据是这次实验的详细记录,第一列([2012/5/21 1:31:00])是当前时间,第二列(80)是前一分钟内爬虫抓取网页的数量n,第三列(3799)是根据3.1式(实际计算中加入了一个积分项,稍后详细说明)计算出来的延时时间(单位为ms),爬虫速度最终稳定在40页/分钟(允许一定的波动)

[2012/5/21 1:31:00] 80  3799
[2012/5/21 1:32:00] 32  4039
[2012/5/21 1:33:00] 30  3980
[2012/5/21 1:34:00] 30  3720
[2012/5/21 1:35:00] 32  3400
[2012/5/21 1:36:00] 36  3200
[2012/5/21 1:37:00] 36  2920
[2012/5/21 1:38:00] 42  2980
[2012/5/21 1:39:00] 40  2980
[2012/5/21 1:40:00] 40  2980
[2012/5/21 1:41:00] 40  2980
[2012/5/21 1:42:00] 40  2980
[2012/5/21 1:43:00] 40  2980
[2012/5/21 1:44:00] 40  2980
[2012/5/21 1:45:00] 40  2980
[2012/5/21 1:46:00] 40  2980
[2012/5/21 1:47:00] 40  2980
[2012/5/21 1:48:00] 40  2980
[2012/5/21 1:49:00] 39  2910
[2012/5/21 1:50:00] 40  2910
[2012/5/21 1:51:00] 41  2980
[2012/5/21 1:52:00] 39  2930
[2012/5/21 1:53:00] 41  3000
[2012/5/21 1:54:00] 40  3000
[2012/5/21 1:55:00] 39  2930

有了PID控制器,在网络环境允许的范围内,想让爬虫每分钟抓几个网页它就抓几个,是不是很方便?

四、完整的PID控制器

  式3.1是一个简化版本的PID控制器,只用到了比例项(P),加入积分项(I)和微分项(D)后才是一个完整的PID控制器。PID是三个英文单词的缩写,分别代表比例单元(Proportion),积分单元(Integral)和微分单元(Differential),每个单元分别对应着一个乘积因子Kp,Ki,Kd。加入积分单元和微分单元后,式3.1扩展为式4.1,其中Sum是误差项(S-n)的积分(其实就是所有误差值的和),Diff是误差项的微分(在单位时间内就是前后两次误差项的差值)

 Tk=Tk-1+Kp*(S-n)+Ki*Sum+Kd*Diff                    (4.1) 

乘积因子Kp,Ki,Kd的设定与具体的应用场景相关,并且需要通过实验来确定其最佳值。如果令Ki=0, Kd=0,那么式4.1就是式3.1了。

五、总结

  第三节中的实验数据是在Kp=-0.05,Ki=-0.01,Kd=0,的条件下获取,其中有一些应用细节上的处理,比如限制最大最小延时时间和限制误差积分项的最大值等。如果需要更深入的了解PID控制器,比如PID算法收敛性和鲁棒性的讨论等,请查阅相关资料,本文更加关注的是如何应用PID控制器。

原文地址:https://www.cnblogs.com/easystep/p/2511468.html