首先我们默认你已经安装node开发环境,node开发IDE (什么webstrom vscode sublime网上很多工具不多做赘述)。以及npm(NodeJS安装包管理工具)
这里我们测试爬虫百家号的不同tab下的新闻列表
爬虫的基本思路
- 通过chrom浏览器请求网站
- 检查元素分析数据的结构
- 通过network分析点击tab网站对应的请求url
- 获取所有tab对应的url进行并发请求
- 解析源码获取对应的新闻数据
- 包装成我们想要的数据结构
创建demo cd到一个空文件夹
1.初始化项目
npm init
2.创建爬虫文件fetch.js
3.通过npm安装superagent、cheerio、async以及url爬虫需要的技术框架
npm install superagent cheerio async url
开始编写爬虫代码
1.首先要引用我们需要的技术框架
//请求网址
var request = require('superagent');
//解析网页源码
var cheerio = require('cheerio');
//控制并发数
var async = require('async');
//url处理
var URL = require('url');
//文件管理
var fs = require('fs');
var path = require('path');
2.第一次请求百家号获取不同tab对应的url
//要爬虫的网站
var bjhVideoUrl = 'https://baijia.baidu.com/';
function startFetch() {
request
.get(bjhVideoUrl)
.end((err,res)=> {
if(err) {
console.log(err);
return;
}
//解析源码获取url
decodeHeaderUrl(res);
});
}
3.根据源码解析网址获取不同url 以及并发请求子tab对应的网页数据
function decodeHeaderUrl(res){
var headerUrls = [];
var $ = cheerio.load(res.text);
$('#header-wrapper .bjh-header-content .bjh-header-list li a').each((idx,element)=> {
var href = $(element).attr('href');
var title = $(element).text().trim();
var headerJson = {
'href':href,
'title':title
};
titleJsons.push(headerJson);
var url = URL.resolve(bjhVideoUrl,href);
console.log(url);
headerUrls.push(url);
});
//通过语法糖async并发请求 headerurls:url数组,2:并发数
async.mapLimit(headerUrls,2,function(url,cb){
requestByTitle(url,cb);
},function(err,result){//全部请求结束之后返回的包装数据数组
console.log('fetch data success! fetch data count ' + result.length);
try {
//数据保存到db.json文件
fs.writeFileSync(path.join(__dirname,'db.json'),JSON.stringify(result,null,2),{'flag':'a'});
console.log('save fetch data to db.json success!');
} catch (error) {
console.log('save fetch data to db.json fail!');
}
});
}
4.解析子tab 来获取我们要的新闻列表数据
var $ = cheerio.load(res.text);
var artEle = $('#articleList')
artEle.children().each((idx,element)=> {
var className = $(element).attr('class');
if (className === 'article-info'){
var imgEle = $(element).find('img');
var imgSrc = $(imgEle).attr('src');
var titleEle = $(element).find('.title').children()[0];
var title = $(titleEle).text().trim();
var authorEle = $(element).find('.author').children()[0];
var author = $(authorEle).text().trim();
var otherEle = $(element).find('.author').children()[1];
var other = $(otherEle).text().trim();
var titleJson = {
'type':className,
'images':[imgSrc],
'title':title,
'author':author,
'other':other
}
videoJsons.push(titleJson);
5.包装我们想要的数据结构
//根据不同tab 对应不同的数据列表
function createResult(url,videos) {
var urlParse = URL.parse(url);
var index = 0;
if (urlParse.query) {
index = parseInt(urlParse.query.substr(4,1));
}
index = index > 0 ?index : 0;
var titleJson = titleJsons[index];
var videoJson = {
'title':titleJson['title'],
'videos':videos
}
return videoJson;
}
6.fetch.js爬虫代码编写完毕,接下来执行fetch文件
node fetch
返回结果如下:
数据被保存到db.json文件如下:
到此爬虫项目就结束了,源码:github
本次爬虫demo使用的相关框架:
*superagent:superagent 是一个轻量的,渐进式的ajax api,可读性好,学习曲线低,内部依赖nodejs原生的请求api。采用链式编程进行方法的调用,通俗易懂,便于理解。我们通过它请求网址获取网页源码。
POST请求用例:
superagent
.post('/api/pet')
.send({ name: 'Manny', species: 'cat' })
.set('X-API-Key', 'foobar')
.set('Accept', 'application/json')
.end(function(res){
if (res.ok) {
alert('yay got ' + JSON.stringify(res.body));
} else {
alert('Oh no! error ' + res.text);
}
});
详细介绍:CNode中文社区
*cheeio:cheerio是nodejs的抓取页面模块,为服务器特别定制的,快速、灵活、实施的jQuery核心实现。适合各种Web爬虫程序。会玩jQuery的朋友相信看一眼就会使用了。通过它来解析我们的网页源码获取我们想要的数据内容。
获取数据用例:
var headerUrls = [];
var $ = cheerio.load(res.text);
$('#header-wrapper .bjh-header-content .bjh-header-list li a').each((idx,element)=> {
var href = $(element).attr('href');
var title = $(element).text().trim();
var headerJson = {
'href':href,
'title':title
};
titleJsons.push(headerJson);
var url = URL.resolve(bjhVideoUrl,href);
console.log(url);
headerUrls.push(url);
});
更多实用方法请上:CNode中文社区
*async:Async 模块是比较有名的异步解决方案,在爬虫过程中如果并发请求较大,有可能会被网站认为恶意攻击,所以我们通过async的eachLimit技术来控制并发数来减少风险。
并发数控制用例:
async.mapLimit(headerUrls,2,function(url,cb){
requestByTitle(url,cb);
},function(err,result){
console.log('fetch data success! fetch data count ' + result.length);
try {
fs.writeFileSync(path.join(__dirname,'db.json'),JSON.stringify(result,null,2),{'flag':'a'});
console.log('save fetch data to db.json success!');
} catch (error) {
console.log('save fetch data to db.json fail!');
}
});