爬虫被源网站流量监控封杀IP?用代理IP来解决

之前一个做了爬虫的客户上周末来找我,希望给爬虫加上代理IP。

并不是所有网站都会监控流量来源,一些运行良好的网站需要考虑数据安全性和核心竞争力,才会对流量进行监控,防止爬虫的高频率抓取导致核心数据外泄。

这部分网站一般是通过IP来识别爬虫,当同个IP在一段时间内请求明显高于人访问网页的速度时,会判定为爬虫请求从而对该请求的IP进行短期或长期封杀。

那这时候就需要使用代理来绕过对IP的监控或封杀。在网上能找到一些提供免费代理IP的平台,不过亲测极其不稳定,通常100个里只有个别能用。

所以真正的想用代理IP来做爬虫,还是找付费的比较好。通常爬虫用途可以买动态IP:平台提供一个API,每次刷新请求会得到一个或一堆有效期比较短的IP,然后从这些IP里挑选来代理请求,失效时重新生成可用的IP即可。

我写的爬虫是node里跑的,这里不得不提的是,在js里非常流行的axios请求库亲测并不能实现代理请求(也许是我姿势不对),参考网上教程需要使用request这个请求库(然而并不好用,API并不是流行的Promise方式)

所以我在逻辑代码里是这样实现的,首先封装一个请求函数,以下是核心示例代码:

const request = require('request') const _ = require('lodash') const _request = (ipList,url) => { return new Promise(async (resolve, reject) => { let useIp = _.sample(ipList); //从ip列表里随机返回一个 const options = { method: 'GET', url: url, gzip: true, encoding: null, proxy: useIp, //动态设置代理ip timeout: 2000 //超时时间,太短代理不稳定,太长请求过久 }; request(options, (error, response, body) => { if (error) >= 0) { console.log(${useIp} 代理有问题); resolve(undefined) return; } console.log(使用代理 ${useIp}) try { let data = JSON.parse(body) resolve(data) } catch (e) { resolve(undefined) } }) }) }

module.exports = async (url) => { try { let result = await _request(url) if (result) return result return axios.get(url).then(res => res.data) } catch (e) { return axios.get(url).then(res => res.data) } } 上面封装过后的请求函数就暴露了一个统一的request方法,使用时候只需要request(url)即可。

从代码里也可以看到:当代理有效时会用代理,当代理无效、超时或其他任何错误时会返回正常的请求,这也是降级保障了爬虫代码的健壮性。

在使用代理IP时,超时时间是个需要不断调整的设置。超时太短了会导致代理不可用的概率提高,而超时太长则会影响整个爬虫的速度。

比如我给客户跑的这个爬虫,不使用代理时跑完需要4个小时,而如果使用代理,每次请求的时间就加长了,在设置2000毫秒的超时下,整个任务跑下来需要翻2倍的时间。