上一篇的批量采集其实只是一个开头,是为了批量采集而搜集大量的url,而本篇文章才是真正的批量采集。
上一篇已经把校花网搜索校花的页面url存入了urlList.txt文件中,在批量采集前需要先读取这个文件:
1 2 3 4 5 6 7 8 9 | 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模块来采集数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | fs.exists(filename, function (stas) { if (stas) { console.log( "存在" ); } else { fs.writeFile(fileName, data, function () { console.log( "不存在" ); }); } }); //对应的同步方法:fs.existsSync(filename);返回true 存在,false 不存在。 //不过我在几次大批量操作中感觉同步方法好像会出现问题,不如fs.exists准确。这个结论我也不确定真假,大家多测试吧 |
于是,一个完整的采集代码是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | 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 条评论。