根据需求所得五个模块javascript
// 请求模块(1.访问网站) const request = require('request'); // 能够看作成node版的jQuery(2.获取页面指定数据源) const cheerio = require("cheerio"); // node异步流程控制 异步循环(3.根据页面数据源再访问详情数据) const async = require("async"); // Excel表格导出+node自带文件系统(4.以Excel形式导出) const excelPort = require('excel-export'); const fs = require("fs");
安装模块:php
npm install request cheerio async excel-export --save-dev
一开始我直接用request请求网站,但直接返回了404,但我在浏览器上看又是没毛病的。而后我就改了下请求的header。嘻嘻html
request({ url: 'http://www.foo.cn?page=1', method: 'get', headers: { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3', // 这里巨坑!这里开启了gzip的话http返回来的是Buffer。 // 'Accept-Encoding': 'gzip, deflate', 'Accept-Language': 'zh-CN,zh;q=0.9', 'Cache-Control': 'no-cache', }, // 想请求回来的html不是乱码的话必须开启encoding为null encoding: null }, (err, res, body) => { // 这样就能够直接获取请求回来html了 console.log('打印HTML', body.toString()); // <html>xxxx</html> } );
request({ url: 'http://www.foo.cn?page=1', method: 'get', headers: { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3', // 'Accept-Encoding': 'gzip, deflate', 'Accept-Language': 'zh-CN,zh;q=0.9', 'Cache-Control': 'no-cache', }, encoding: null }, (err, res, body) => { console.log('打印HTML', body.toString()); // <html>xxxx</html> const list = []; const $ = cheerio.load(body.toString()); // 获取指定元素 let item = $('.className tbody tr'); // 循环获得元素的跳转地址和名称 item.map((i, index) => { let obj = {}; obj.link = $(index).children('a').attr('href'); obj.name = $(index).children('a').text(); list.push(obj); }); console.log('list', list); // [{ link: 'http://xxxx.com', name: 'abc' }] } );
先将request封装多一层,传入page值和async.series的callbackjava
async function requestPage(page = 1, callback) { request({ url: 'http://www.masuma.cn/product.php?lm=21&page=' + page, method: 'get', headers: { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3', // 'Accept-Encoding': 'gzip, deflate', 'Accept-Language': 'zh-CN,zh;q=0.9', 'Cache-Control': 'no-cache', }, encoding: null }, async (err, res, body) => { console.log('打印HTML', body.toString()); // <html>xxxx</html> const list = []; const $ = cheerio.load(body.toString()); // 获取指定元素 let item = $('.className tbody tr'); // 循环获得元素的跳转地址和名称 item.map((i, index) => { let obj = {}; obj.link = $(index).children('a').attr('href'); obj.name = $(index).children('a').text(); list.push(obj); }); console.log('list', list); // [{ link: 'http://xxxx.com', name: 'abc' }] callback(null, list); } ); }
async function main() { const requestList = []; // 在这里为何要用到async.series? // 是由于这个爬虫须要具备顺序性,必须得异步请求完一个地址并获取数据而后再存到一个变量里才能执行下一个 // 在此期间我想过其余方法。例如: // for循环 + await 直接否认了 // Promise.all这个并不能保证数据具备顺序 // 最终敲定用async.series 用完以后!真香啊! // 很好奇async.series找个时间也作个源码解析 for (let i = 1; i < 36; i++) { requestList.push(callback => { requestPage(i, callback); }); } console.log('requestList', requestList); // [Function, Function] 全是function的数组 async.series(requestList, (err, result) => { // 由于async.series返回来的结果是[[], [], []]这种二维数组形式,每一个function返回来的值都放在一个数组里,咱们须要将它弄成一维数组好作导出列表 const arry = [].concat.apply([], result); console.log('最终结果!!!!', arry); // [{ link: 'http://xxxx.com', name: 'abc' }, ...] writeExcel(arry); }); } const writeExcel = (datas) => { // 定义一个对象,存放内容 let conf = {}; // 定义表头 conf.cols = [ {caption:'玛速玛编码', type:'string', width:40}, {caption:'原厂编码', type:'string', width:60}, ]; // 建立一个数组用来屡次遍历行数据 let array = []; // 循环导入从传参中获取的表内容 for (let i=0;i<datas.length;i++){ //依次写入 array[i] = [ datas[i].name, datas[i].code, ]; } // 写入道conf对象中 conf.rows = array; // 生成表格 const result = excelPort.execute(conf); // 定义表格存放路径 fs.writeFile('./表格.xlsx', result, 'binary',function(err){ if(err){ console.log(err); } }); } main();
其实爬虫就是:node
其实这个爬虫最终是web
但我在这里就写了获取各页表格里的连接地址,由于在这里我只想作一个简单的分享。数据库
这些分享应该都足以举一反三了。npm