上一篇的批量采集其实只是一个开头,是为了批量采集而搜集大量的url,而本篇文章才是真正的批量采集。
上一篇已经把校花网搜索校花的页面url存入了urlList.txt文件中,在批量采集前需要先读取这个文件:
fs.readFile('urlList.txt', function (err, data) {
if (err) {
return false;
} else {
var urls = data.toString();//将读取的内容转换成字符串
var urlsArr=urls.split(',');//将字符串转换成数组,便于遍历
console.log(urlsArr);
}
});
接下来大家的思路可能是直接for循环遍历数组urlsArr,然后调用上一篇封装好的spider模块来采集数据:
var http = require('http');
var fs = require('fs');
var spider = require('./spider');
fs.readFile('urlList.txt',
function(err, data) {
if (err) {
return false;
} else {
var urls = data.toString(); //将读取的内容转换成字符串
var urlsArr = urls.split(','); //将字符串转换成数组,便于遍历
for (var i in urlsArr) {
spider(urlsArr[i], null,
function(data) {
console.log(data)
});
}
}
});
以上代码可以保存为getDetails.js文件,执行过程发现会报各种错误,同时又会console.log出很多结果,导致的原因很简单:for循环会瞬间发出大量请求,导致对方服务器受不了压力而直接拒绝。所以大批量采集数据的时候要考虑到并发的处理,同理,其他的大量的异步操作也要考虑并发的处理。
nodejs处理异步操作的方式有很多,比如Async、Promise等。本教程采取Async。Async用法参考:http://blog.fens.me/nodejs-async/
var http = require('http');
var fs = require('fs');
var async = require('async');
var spider = require('./spider');
fs.readFile('urlList.txt',
function(err, data) {
if (err) {
return false;
} else {
var urls = data.toString(); //将读取的内容转换成字符串
var urlsArr = urls.split(','); //将字符串转换成数组,便于遍历
async.eachLimit(urlsArr, 1,
function(file, callback) {
spider(file, null,
function(data) {
cosole.log(data);
callback(); //必须添加,不然没办法走下一流程
});
},
function(err, result) {
console.log('All Success');
});
}
});
这样便控制了并发数。接下来要做的就是跟第三篇“数据的筛选:cheerio模块”那一章要做的一样了,提取核心内容,然后保存成对应的html文件。
不过有些地方可以稍微改进一下。因为是批量进行采集,有时候即使控制并发数也不能保证对方服务器不卡死,所以我们免不了需要多次执行getDetails.js文件,但是有些已经采集成功的页面没必要再重新采集,所以可以在采集之前判断本地有没有保存该页面的html文件,如果有,则跳过,没有则采集。
判断文件是否存在则需要fs模块的exists方法。
fs.exists(filename,
function(stas) {
if (stas) {
console.log("存在");
} else {
fs.writeFile(fileName, data,
function() {
console.log("不存在");
});
}
});
//对应的同步方法:fs.existsSync(filename);返回true 存在,false 不存在。
//不过我在几次大批量操作中感觉同步方法好像会出现问题,不如fs.exists准确。这个结论我也不确定真假,大家多测试吧
于是,一个完整的采集代码是这样的:
var http = require('http');
var cheerio = require('cheerio');
var iconv = require('iconv-lite');
var BufferHelper = require('bufferhelper');
var fs = require('fs');
var async = require('async');
var spider = require('./spider');
fs.readFile('urlList.txt',
function(err, data) {
if (err) {
return false;
} else {
var urls = data.toString();
var urlArr = urls.split(',');
async.eachLimit(urlArr, 1,
function(eachUrl, callback) {
var fileName = 'detail/' + eachUrl.replace(/http:\/\/www.xiaohuar.com\//, '');
fs.exists(fileName,
function(stas) {
if (stas) {
console.log(fileName + "已存在");
callback();
} else {
spider(eachUrl, null,
function(data) {
var val = iconv.decode(data.toBuffer(), 'gb2312');
var $ = cheerio.load(val, {
decodeEntities: false
}); //decodeEntities: false 避免乱码
var title = "<title>" + $(".wrap h1").html() + "</title>";
var contentObj = $(".content_wrap");
contentObj.find(".gg4,a").remove();
contentObj.find("p,img,span").each(function() {
$(this).removeAttr("class");
$(this).removeAttr("style");
$(this).removeAttr("alt");
$(this).removeAttr("title");
$(this).removeAttr("id");
});
var contentHtml = contentObj.html();
contentHtml = contentHtml.replace(/<span>/g, '');
contentHtml = contentHtml.replace(/<\/span>/g, '');
contentHtml = contentHtml.replace(/src="\/d\/file/g, 'src="http://www.xiaohuar.com/d/file');
contentHtml = "<content>" + contentHtml + "</content>";
var mainHtml = title + contentHtml;
fs.writeFile(fileName, mainHtml,
function() {
console.log(fileName + '==>success');
callback();
});
});
}
});
},
function(err, result) {
console.log('All Success');
});
}
});
文末强行扣题——Async模块相关知识都在这里了:http://blog.fens.me/nodejs-async/ 我也是看的这篇文章,就没必要再把人家的内容贴过来了。。。
0 条评论。