前言
几个月之前,有同事找我要php CI框架写的OA系统。他跟我说,他需要学习PHP CI框架,我建议他学习大牛写的国产优秀框架QeePHP。
我上QeePHP官网,发现官方网站打不开了,GOOGLE了一番,发现QeePHP框架已经没人维护了。API文档资料都没有了,那可怎么办?
毕竟QeePHP学习成本挺高的。GOOGLE时,我发现已经有人把文档整理好,放在自己的个人网站上了。我在想:万一放文档的个人站点也挂了,
怎么办?还是保存到自己的电脑上比较保险。于是就想着用NodeJS写个爬虫抓取需要的文档到本地。后来抓取完成之后,干脆写了一个通用版本的,
可以抓取任意网站的内容。
爬虫原理抓取初始URL的页面内容,提取URL列表,放入URL队列中,从URL队列中取一个URL地址,抓取这个URL地址的内容,提取URL列表,放入URL队列中
。。。。。。。。。。。。
NodeJS实现源码
1 /** 2 * @desc 网页爬虫 抓取某个站点 3 * 4 * @todolist 5 * URL队列很大时处理 6 * 302跳转 7 * 处理COOKIE 8 * iconv-lite解决乱码 9 * 大文件偶尔异常退出 10 * 11 * @author WadeYu 12 * @date 2015-05-28 13 * @copyright by WadeYu 14 * @version 0.0.1 15 */ 16 17 /** 18 * @desc 依赖的模块 19 */ 20 var fs = require("fs"); 21 var http = require("http"); 22 var https = require("https"); 23 var urlUtil = require("url"); 24 var pathUtil = require("path"); 25 26 /** 27 * @desc URL功能类 28 */ 29 var Url = function(){}; 30 31 /** 32 * @desc 修正被访问地址分析出来的URL 返回合法完整的URL地址 33 * 34 * @param string url 访问地址 35 * @param string url2 被访问地址分析出来的URL 36 * 37 * @return string || boolean 38 */ 39 Url.PRototype.fix = function(url,url2){ 40 if(!url || !url2){ 41 return false; 42 } 43 var oUrl = urlUtil.parse(url); 44 if(!oUrl["protocol"] || !oUrl["host"] || !oUrl["pathname"]){//无效的访问地址 45 return false; 46 } 47 if(url2.substring(0,2) === "//"){ 48 url2 = oUrl["protocol"]+url2; 49 } 50 var oUrl2 = urlUtil.parse(url2); 51 if(oUrl2["host"]){ 52 if(oUrl2["hash"]){ 53 delete oUrl2["hash"]; 54 } 55 return urlUtil.format(oUrl2); 56 } 57 var pathname = oUrl["pathname"]; 58 if(pathname.indexOf('/') > -1){ 59 pathname = pathname.substring(0,pathname.lastIndexOf('/')); 60 } 61 if(url2.charAt(0) === '/'){ 62 pathname = ''; 63 } 64 url2 = pathUtil.normalize(url2); //修正 ./ 和 ../ 65 url2 = url2.replace(////g,'/'); 66 while(url2.indexOf("../") > -1){ //修正以../开头的路径 67 pathname = pathUtil.dirname(pathname); 68 url2 = url2.substring(3); 69 } 70 if(url2.indexOf('#') > -1){ 71 url2 = url2.substring(0,url2.lastIndexOf('#')); 72 } else if(url2.indexOf('?') > -1){ 73 url2 = url2.substring(0,url2.lastIndexOf('?')); 74 } 75 var oTmp = { 76 "protocol": oUrl["protocol"], 77 "host": oUrl["host"], 78 "pathname": pathname + '/' + url2, 79 }; 80 return urlUtil.format(oTmp); 81 }; 82 83 /** 84 * @desc 判断是否是合法的URL地址一部分 85 * 86 * @param string urlPart 87 * 88 * @return boolean 89 */ 90 Url.prototype.isValidPart = function(urlPart){ 91 if(!urlPart){ 92 return false; 93 } 94 if(urlPart.indexOf("javascript") > -1){ 95 return false; 96 } 97 if(urlPart.indexOf("mailto") > -1){ 98 return false; 99 }100 if(urlPart.charAt(0) === '#'){101 return false;102 }103 if(urlPart === '/'){104 return false;105 }106 if(urlPart.substring(0,4) === "data"){//base64编码图片107 return false;108 }109 return true;110 };111 112 /**113 * @desc 获取URL地址 路径部分 不包含域名以及QUERYSTRING114 *115 * @param string url116 *117 * @return string118 */119 Url.prototype.getUrlPath = function(url){120 if(!url){121 return '';122 }123 var oUrl = urlUtil.parse(url);124 if(oUrl["pathname"] && (///$/).test(oUrl["pathname"])){125 oUrl["pathname"] += "index.html";126 }127 if(oUrl["pathname"]){128 return oUrl["pathname"].replace(/^//+/,'');129 }130 return '';131 };132 133 134 /**135 * @desc 文件内容操作类136 */137 var File = function(obj){138 var obj = obj || {};139 this.saveDir = obj["saveDir"] ? obj["saveDir"] : ''; //文件保存目录140 };141 142 /**143 * @desc 内容存文件144 *145 * @param string filename 文件名146 * @param mixed content 内容147 * @param string charset 内容编码148 * @param Function cb 异步回调函数149 * @param boolean bAppend 150 *151 * @return boolean152 */153 File.prototype.save = function(filename,content,charset,cb,bAppend){154 if(!content || !filename){155 return false;156 }157 var filename = this.fixFileName(filename);158 if(typeof cb !== "function"){159 var cb = function(err){160 if(err){161 console.log("内容保存失败 FILE:"+filename);162 }163 };164 }165 var sSaveDir = pathUtil.dirname(filename);166 var self = this;167 var cbFs = function(){168 var buffer = new Buffer(content,charset ? charset : "utf8");169 fs.open(filename, bAppend ? 'a' : 'w', 0666, function(err,fd){170 if (err){171 cb(err);172 return ;173 }174 var cb2 = function(err){175 cb(err);176 fs.close(fd);177 };178 fs.write(fd,buffer,0,buffer.length,0,cb2);179 });180 };181 fs.exists(sSaveDir,function(exists){182 if(!exists){183 self.mkdir(sSaveDir,"0666",function(){184 cbFs();185 });186 } else {187 cbFs();188 }189 });190 };191 192 /**193 * @desc 修正保存文件路径194 *195 * @param string filename 文件名196 *197 * @return string 返回完整的保存路径 包含文件名198 */199 File.prototype.fixFileName = function(filename){200 if(pathUtil.isAbsolute(filename)){201 return filename;202 }203 if(this.saveDir){204 this.saveDir = this.saveDir.replace(/[///]$/,pathUtil.sep);205 }206 return this.saveDir + pathUtil.sep + filename;207 };208 209 /**210 * @递归创建目录211 *212 * @param string 目录路径213 * @param mode 权限设置214 * @param function 回调函数215 * @param string 父目录路径216 *217 * @return void218 */219 File.prototype.mkdir = function(sPath,mode,fn,prefix){220 sPath = sPath.replace(///+/g,'/');221 var aPath = sPath.split('/');222 var prefix = prefix || '';223 var sPath = prefix + aPath.shift();224 var self = this;225 var cb = function(){226 fs.mkdir(sPath,mode,function(err){227 if ( (!err) || ( ([47,-4075]).indexOf(err["errno"]) > -1 ) ){ //创建成功或者目录已存在228 if (aPath.length > 0){229 self.mkdir( aPath.join('/'),mode,fn, sPath.replace(///$/,'')+'/' );230 } else {231 fn();232 }233 } else {234 console.log(err);235 console.log('创建目录:'+sPath+'失败');236 }237 });238 };239 fs.exists(sPath,function(exists){240 if(!exists){241 cb();242 } else if(aPath.length > 0){243 self.mkdir(aPath.join('/'),mode,fn, sPath.replace(///$/,'')+'/' );244 } else{245 fn();246 }247 });248 };249 250 /**251 * @递归删除目录 待完善 异步不好整252 *253 * @param string 目录路径254 * @param function 回调函数255 *256 * @return void257 */258 File.prototype.rmdir = function(path,fn){259 var self = this;260 fs.readdir(path,function(err,files){261 if(err){262 if(err.errno == -4052){ //不是目录263 fs.unlink(path,function(err){264 if(!err){265 fn(path);266 }267 });268 }269 } else if(files.length === 0){270 fs.rmdir(path,function(err){271 if(!err){272 fn(path);273 }274 });275 }else {276 for(var i = 0;
新闻热点
疑难解答