内容简介:还记得刚学爬虫的时候,选了一个美女网站来练手,效率极高,看到什么都想爬下来。爬得正高兴呢,出现了一连串错误信息,查看后发现因为爬取太过频繁,被网站封了ip,那时起就有了构建代理ip池的念头。网上搜索一下代理ip就会发现有很多网站提供,但是稳定好用的都要收费,免费倒也有一堆,但大多数都不能用。而且我写的一般都是小爬虫,极少有爬取上白g数据的时候,用收费的代理ip有点浪费。所以,写了这个代理ip池,从各大代理ip网站爬取收集免费的代理ip,然后一一进行测试,从中筛选出高速可用的ip。得益于Node的异步架构,速
还记得刚学爬虫的时候,选了一个美女网站来练手,效率极高,看到什么都想爬下来。爬得正高兴呢,出现了一连串错误信息,查看后发现因为爬取太过频繁,被网站封了ip,那时起就有了构建代理ip池的念头。
网上搜索一下代理ip就会发现有很多网站提供,但是稳定好用的都要收费,免费倒也有一堆,但大多数都不能用。而且我写的一般都是小爬虫,极少有爬取上白g数据的时候,用收费的代理ip有点浪费。
所以,写了这个代理ip池,从各大代理ip网站爬取收集免费的代理ip,然后一一进行测试,从中筛选出高速可用的ip。得益于Node的异步架构,速度非常快,可以直接在自己的爬虫里调用,每次爬取前获取最新的代理ip,以后妈妈就再也不用担心我的爬虫被封了。
接下来会分为三个部分来讲解,怎么下载,怎么用和怎么写,如果只是想用的话看前两篇就够了。
##1.如何下载
有两种途径,一个是通过Github:Card007/Proxy-Pool;
另一种是通过npm添加:npm install ip-proxy-pool;
两种方式都可以,推荐github,有个使用说明,后期我还会进行更新,欢迎start。
##2.如何使用
//导入本地模块 var proxy = require('./proxy_pool.js') //如果通过npm安装 //var proxy = require('ip-proxy-pool') //主程序,爬取ip+检查ip var proxys = proxy.run //不爬取,只检查数据库里现有的ip var check = proxy.check //提取数据库里所有的ip var ips = proxy.ips //ips接收一个处理函数,然后向这个函数传递两个参数,一个为错误信息,另一个为数据库里的所有ip ips((err,response)=>{ console.log(response) }) //如果希望爬取的ip多一点可以修改check函数里的timeout 复制代码
##3.怎么手动写一个代理ip池
现在来说说自己怎么写一个代理ip池,以西刺为例,用到的 工具 和方法基本上和上一篇爬取豆瓣top250一样,先是爬取西刺网站前5页的所有免费ip,然后保存在 sqlite 数据库里,然后通过一一使用爬取好的代理ip访问某个网址,返回200的则是可用,返回其它数字的则删除,来看代码:
//导入相应的库 var request = require('request') var cheerio = require('cheerio') var sqlite3 = require('sqlite3') //生成网址,西刺网址以尾号数字作为分页链接 var ipUrl = function(resolve){ var url = 'http://www.xicidaili.com/nn/' var options = { url:'http://www.xicidaili.com/nn/', headers, } //用个简单的for循环即可获得所有需要的链接,然后将链接一一放到爬取网络的requestProxy里 for (let i = 1; i <= 5; i++) { options.url = url + i requestProxy(options) } } //链接网络 var requestProxy = function(options){ //这里使用了Promise来控制异步 return new Promise((resolve, reject) => { request(options, function(err, response, body){ if(err === null && response.statusCode === 200){ //返回200说明爬取成功,loadHtml为解析函数,会将我们需要的信息爬取出来存在数据库里 loadHtml(body) resolve() } else { console.log('链接失败') resolve() } }) }) } 复制代码
接下来要说到Node的大坑,异步,由于异步架构,需要用到Promise来控制,比如在这个代理ip池里,会出现reqeust函数还没有爬完的时候就开始执行验证函数,很容易出错,所以我们需要分为两组,一组为异步爬取网站爬取,另一组为异步验证代理ip,所以我们来改造一下上面的代码:
//生成网址 var ipUrl = function(resolve){ var url = 'http://www.xicidaili.com/nn/' var options = { url:'http://www.xicidaili.com/nn/', headers, } var arr = [] for (let i = 1; i <= 5; i++) { options.url = url + i arr.push(requestProxy(options)) } //Promise.all接收一个数组,直到数组里所有的函数执行完毕才执行后面then里的内容 //实际上放这里有点多余,后期会改过来,先将就 Promise.all(arr).then(function(){ resolve() }) } //链接网络 var requestProxy = function(options){ return new Promise((resolve, reject) => { request(options, function(err, response, body){ if(err === null && response.statusCode === 200){ loadHtml(body) resolve() } else { console.log('链接失败') resolve() } }) }) } 复制代码
接下来分析一下网页内容,这里我们只需要ip,端口,和类型即可:
//分析网页内容 var loadHtml = function(data){ var l = [] var e = cheerio.load(data) e('tr').each(function(i, elem){ l[i] = e(this).text() }) for (let i = 1; i < l.length; i ++){ //在提取到想要的内容后发现太乱,需要额外的函数进行处理优化 clearN(l[i].split(' ')) } } //提取优化文件数据, var clearN = function(l){ var index = 0 for (let i = 0; i < l.length; i++) { if(l[i] === '' || l[i] === '\n'){ }else{ var ips = l[i].replace('\n','') if (index === 0){ var ip = ips console.log('爬取ip:' + ip) } else if(index === 1){ var port = ips } else if(index === 4){ var type = ips } index += 1 } } //存入数据库 insertDb(ip, port, type) } 复制代码
接着来实现数据库的存储删除功能:
//打开数据库 var db = new sqlite3.Database('Proxy.db', (err) => { if(!err){ console.log('打开成功') } else { console.log(err) } }) db.run('CREATE TABLE proxy(ip char(15), port char(15), type char(15))',(err) => {}) //添加数据文件 var insertDb = function(ip, port, type){ db.run("INSERT INTO proxy VALUES(?, ?, ?)",[ip,port,type]) } //删除数据库文件 var removeIp = function(ip){ db.run(`DELETE FROM proxy WHERE ip = '${ ip }'`, function(err){ if(err){ console.log(err) }else { console.log('成功删除:'+ip) } }) } //从数据库提取所有ip var allIp = function(callback){ return db.all('select * from proxy', callback) } 复制代码
接着将数据库里的ip提取出来,进行测速筛选:
//从数据库提取出来的ip会通过这个类创建一个对象 var Proxys = function(ip,port,type){ this.ip = ip this.port = port this.type = type } //提取所有ip,通过check函数检查 var runIp = function(resolve){ var arr = [] allIp((err,response) => { for (let i = 0; i < response.length; i++) { var ip = response[i] var proxy = new Proxys(ip.ip, ip.port, ip.type) arr.push(check(proxy, headers)) } Promise.all(arr).then(function(){ allIp((err, response)=>{ console.log('\n\n可用ip为:') console.log(response) }) }) }) } //检测ip var check = function(proxy, headers){ return new Promise((resolve, reject) => { request({ //检测网址为百度的某个js文件,速度快,文件小,非常适合作为检测方式 url:'http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js', proxy: `${proxy.type.toLowerCase()}://${proxy.ip}:${proxy.port}`, method:'GET', //这里延迟使用了2000,如果希望通过检测的ip多一些,可以适当延长 timeout: 2000, headers,} ,function(err, response,body){ if(!err && response.statusCode == 200){ console.log(proxy.ip+' 链接成功:') resolve() } else { console.log(proxy.ip+' 链接失败') removeIp(proxy.ip) resolve() } } ) }) } 复制代码
最后,来写几个运行函数:
var run = function(){ new Promise(ipUrl).then(runIp) } var rcheck= function(){ runIp() } var ips = function(callback){ allIp(callback) } 复制代码
大功告成:
完整代码可以通过Github查看: Proxy-Pool
也可以访问我的网站,获取更多文章:Nothlu
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 如何构建一个分布式爬虫:基础篇
- 基于Vert.x和RxJava 2构建通用的爬虫框架
- EasySelect 1.1.0 发布,能够快速构建爬虫的浏览器插件
- 爬虫需谨慎,那些你不知道的爬虫与反爬虫套路!
- 反爬虫之字体反爬虫
- 反爬虫之字体反爬虫
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。