由于之前一直在做爬虫采集相关的开发,这个过程那肯定少不了跟「代理 IP」打交道,这篇文章就来记录一下,如何实现一个爬虫代理服务,本篇文章主要以讲解思路为主。
起因
做过爬虫的人应该都知道,抓的网站和数据多了,如果爬虫抓取速度过快,免不了触发网站的防爬机制。而这些网站应对爬虫的办法,几乎用的同一招就是封 IP 。
那么我们还想稳定、持续地抓取这些网站的数据,如何解决呢?一般解决方案有2个:
- 使用同一个服务器 IP 抓取网站数据,但是放慢速度
- 使用多个代理 IP 抓取数据
第一种方案牺牲的是时间和速度,但是一般情况下我们的时间是很宝贵的,理想情况下是,用最短的时间获取最多的数据。所以第二种方案是推荐的,那么从哪里可以找到这么多代理 IP 呢?
寻找代理
最直接地,使用搜索引擎去检索。
例如使用 Google、Bing、百度,输入关键字:免费代理 IP,前几页几乎都是提供代理 IP 的网站,逐个打开后观察可以发现,几乎都是一个列表页,这个列表页展示的代理 IP 少则几十个、多则几百个。
但是仔细观察你就会发现,每个网站提供的免费 IP 是有限的,而且拿来用之后你就会发现,有的也已经失效了。毕竟,人家更倾向于你购买他们的付费代理 IP。
身为狡猾的程序猿,当然不能因为这点困难就退缩了。仔细想一下,既然搜索引擎能搜到这么多提供代理的网站,每个网站提供几十或几百个代理 IP,假如有 10 家代理网站,那加在一起也有几百到几千个了。
那么很简单,你要做的事情就是,把这些提供代理 IP 的网站收集起来,写一个采集程序把这些免费代理 IP 抓过来就好了,想想是不是很简单?
测试代理
好了,通过刚才的思路,你可以编写一个采集代理 IP 的程序,然后就可以拿到成百上千的代理 IP 了。当然,收集的代理网站越多,采集到的代理 IP 也就越多,所以我们尽量多收集一些代理网站,越多越好。
等等,这么多代理 IP ,难道别人真的就免费送给你了吗?
当然不是,前面也提到过,这些代理中,有很大一部分已经是失效的了。那怎么办?如何知道哪些代理是有效,哪些是不可用的呢?
很简单,写一个 HTTP 程序,挂上这些代理,访问某一个稳定的网站,然后看是否能正常访问,如果可以正常访问,那么代理 IP 就是可用的,访问失败则说明代理 IP 已失效。
最简单地,我们可以使用 curl
命令就可以测试一个代理是否真的可用:
1 | # 使用代理 48.139.133.93:3128 访问 网易首页 |
当然,这种方式只是为了演示方便,实际最好的方式是:编写一个多线程的代理测试程序,然后分别使用这些代理去访问某个网站,根据访问的结果,最终就可以输出一批可用的代理 IP。
使用代理
通过编写测试代理 IP 的程序,我们就可以找出可用的代理了。
接下来,如何使用也就变得很简单了。
例如,我们把刚才得到的可用代理 IP 输出到一个文件中,每一行是一个 IP,那么我们的程序就可以这样使用:
- 程序读取代理文件,加载代理列表到数组中
- 从数组中随机选择一个代理 IP,发起 HTTP 请求
这样下来,如果可用的代理 IP 稳定在几百上千个,基本上可以保持一段时间抓取某个网站的数据了,一般来说,抓个几千几万条数据不成问题。
但是,如果我想持续不断地从某个网站采集数据,或者是抓取上百万甚至上亿的网页数据,这一批代理 IP 还是有可能逐渐都失效的。这种情况下怎么办呢?
持续不断供应代理
使用刚才的方式,抓取一批代理网站,然后通过测试程序输出可用的代理 IP 列表,但是这只是一次性的,而且代理 IP 的数量往往很少,在我们的持续采集需求中,肯定无法满足需要。那么怎么才能持续不断的找到可用代理 IP 呢?
依据前面所说的方法,我们可以这样优化:
- 收集更多的代理 IP 网站(数据基础)
- 定时监控这些网站,采集代理 IP 列表
- 程序自动检测代理 IP 可用性,输出可用代理 IP(文件或数据库)
- 程序加载文件或数据库,随机选取代理 IP 发起 HTTP 请求
按照这种优化思路,我们可以写出一个自动采集代理 IP 的程序。这样我们的爬虫端就可以定时去文件/数据库中获取可用的代理 IP 使用。
但是有一个小问题,怎样知道每个代理 IP 的质量如何?也就是说,每个代理 IP 的速度怎么样?
我们在测试代理 IP 的可用性时,可以记录访问网站请求响应时间,这个响应时间就是代理 IP 的质量。响应时间越短,说明代理 IP 的质量越高。
有了代理 IP 的质量后,我们在使用这些代理 IP 时,就可以优先使用质量高的,提高我们爬虫抓取网页的成功率。
但是也不能一直频繁使用这些高质量的代理 IP,否则对方网站会很快把这些 IP 封禁掉。那如何应对呢?
我们继续优化,在使用代理 IP 时,我们可以限制某短时间内同一个 IP 的使用次数,例如 5 分钟内同一个代理 IP 只允许使用 10 次,如果超过使用次数了,再随机选取其他代理 IP 使用。
这样既然保证我们的抓取质量,也能保证代理 IP 不会因为短时间内大量使用而被封禁。
服务化
经过前面一系列的优化,我们已经搭建好一个可用的代理服务,只不过是基于文件或数据库的。
爬虫端要想使用这些代理,只能是读取文件或数据库,然后根据某种规则选择代理 IP 使用,这样做比较繁琐,能不能让爬虫端使用代理变得简单一些?此时我们就需要把代理访问做成服务化。
有个大名鼎鼎的服务器软件 squid
,它是一个正向代理软件。利用它的 cache_peer
机制,就可以帮这个事情做得很好。
我们可以把可用的代理 IP 列表,根据 squid
的 cache_peer
规则,按照一定格式,写在它配置文件中即可。而且 cache_peer
配置文件规则,也支持设置每个代理 IP 的使用权重、最大使用次数,也就是说 squid
可以根据配置,自动地调度、选择我们的代理 IP。
配置完成后,启动 squid
,我们就可以通过 squid
的这一个端口来使用配置好的代理 IP 了。
假设我们的爬虫部署在 A 服务器,squid
部署在 B 服务器,需要爬取的网站服务器是 C,而我们的代理 IP 是D/E/F。
- 不使用代理时:爬虫服务器 A 直接请求网站服务器 C
- 正常使用代理时:爬虫服务器 A,通过设置代理 IP D / E / F,请求网站服务器 C
- 使用
squid
时:爬虫服务器 A,通过部署在服务器B的squid
的cache_peer
机制,自动调度代理 IP D / E / F,最终访问网站服务器 C
可见,使用 squid
的好处是:爬虫端不用考虑如何加载和选择代理,只需要把代理 IP 列表按照配置文件的规则,配置到 squid
中,squid
就可以帮我们管理和选择代理。最重要的是,爬虫端使用代理只需配置 squid
的这一个端口就可以了!
整合
好了,现在服务化也搭建完成了,唯一还差的一步就是整合,我们把整个过程梳理一下:
1、收集尽可能多的代理网站,使用采集代理 IP 程序定时采集代理网站(30分/1小时都可),解析出所有代理 IP,写入数据库
2、代理测试程序从数据库中取出所有代理 IP,然后挂上代理,访问某个稳定的网站,根据访问结果,在数据库中标记代理是否可用,同时,也在数据库中记录访问网站的响应时间
3、写一个程序,从数据库中加载出所有可用代理,根据代理响应时间,计算一个使用权重和设置好最大使用次数,按照 cache_peer
格式写入到 squid
的配置文件中
4、写一个程序或脚本,触发自动重新加载 squid
配置文件,让 squid
加载最新的代理 IP 列表
5、定时重复1-4,不断输出可用代理到 squid
中
6、爬虫指定 squid
的服务 IP 和端口,进行纯粹的网站采集操作
通过以上方式,一个完整的代理服务就可以搭建完成,而且这个代理服务可以定时输出保证质量的代理 IP。爬虫端不用关心代理的采集和测试,只管使用 squid
的统一服务入口爬取数据即可。
以上只是提供一个代理服务搭建的设计思路,有了思路之后,剩下写代码实现就变得比较简单了。