nodejs是服务器端的语言,所以可以像python一样对网站进行爬取。
准备
1.项目初始化,执行npm init,来初始化package.json 2.npm install request —save 3.npm install async --save
文件中需要引入的包 var request = require('request'); var fs = require('fs'); var async = require('async');
思路
爬虫分两种情况,第一种是用cheerio模块,获取到html的节点,从节点中拿到数据,比较适合直接用后端语言来渲染的页面。第二种是通过调用爬取网站的接口请求数据。
首先我们需要在XHR中找到获取关注列表的API。我们要做的就是通过这个api来获取大量的用户数据,再对用户信息处理。找到我们想得到的数据。
请求api需要在请求的头部加上登陆之后的authorization信息才能成功。
代码
// 项目初始化,执行npm init,来初始化package.json // npm install request--save // npm install async --save // 需要引入的包 var request = require('request'); var fs = require('fs'); var async = require('async'); var url = "https://www.zhihu.com/api/v4/members/mu-rong-qi-95/followers?include=data%5B*%5D.answer_count%2Carticles_count%2Cgender%2Cfollower_count%2Cis_followed%2Cis_following%2Cbadge%5B%3F(type%3Dbest_answerer)%5D.topics&offset=0&limit=20"; //request请求的options var options = { url: url, headers: { "authorization": "Bearer Mi4wQUJCQ0hCNXVDUXNBUU1LUUtCanlDeGNBQUFCaEFsVk5Ca3h4V1FEcS1Vc1VScVY1Qko5SWpuRkFSY3R0bVA2YWZB|1498005254|1140b230de84e46ff818902c8f0da250ac6c6dd2" } } var users=[]; // 获取大量的用户数据 function getDataList(url) { options.url = url; request.get(options, function(error, response, body) { if(!error&&response.statusCode == 200) { var response = JSON.parse(response.body); var zhList = response.data; zhList.forEach(function(item) { //item.gender == 0 性别判断 if(item.gender == 1) { console.log(`正在抓取${item.avatar_url}`) users.push({ "name": item.name, "img": item.avatar_url.replace("_is", ""), "url_token": item.url_token }) } }) //is_end当前用户的关注用户是否到最后一页 if(response.paging.is_end) { //这里判断抓取的条数 if(users.length<= 1000) { console.log(`抓取完成`); downLoadContent(JSON.stringify(users)); return; } else { console.log(`第${i+1}个用户的数据`); getDataList(zurl.replace("demouser", users[i].url_token)) i++; } } else { if(users.length<= 1000) { console.log(`抓取完成`); downLoadContent(JSON.stringify(users)); return; } getDataList(response.paging.next); } } }) } // 把数据下载保存到data.js function downLoadContent(cont) { fs.appendFile('./' + 'data.js', "module.exports =" + cont, 'utf-8', function(err) { if(err) { console.log(err); } else console.log('success'); startDownLoad(JSON.parse(cont)); }); } // 下载图片 var eyeUrl = "http://api.eyekey.com/face/Check/checking"; var config = { "app_id": "f89ae61fd63d4a63842277e9144a6bd2", "app_key": "af1cd33549c54b27ae24aeb041865da2", "url": "https://pic4.zhimg.com/43fda2d268bd17c561ab94d3cb8c80eb.jpg" } function face(item) { config.url = item.img; request.post({ url: eyeUrl, form: config }, function(error, response, body) { if(!error&&response.statusCode == 200) { var data = JSON.parse(body); try { if(data.face[0].attribute.gender == 'Female') { console.log(`正在下载${item.img}`); downLoadImg(item) } } catch(e) { console.log(`验证失败${item.img}~`); } } }) } // 下载图片方法 function downLoadImg(image) { request.head(image.img, function(err, res, body) { if(err) { console.log(err); } }); request(image.img).pipe(fs.createWriteStream('./beauty_image/' + image.name + Date.now() + '.' + image.img.substring(image.img.lastIndexOf(".") + 1, image.img.length))); } // 开始下载 function startDownLoad(imgdata){ //控制并发量,在5个以内 console.log(imgdata) async.eachLimit(imgdata, 3, function (item, callback) { face(item); callback(); }, function (err) { if(err) { console.log(err); } else { console.log('success!'); } }); } getDataList(url);
启动
node crawl.js
应用cheerio模块从dom节点取数据
var http = require('http'); var fs = require('fs'); var cheerio = require('cheerio'); var request = require('request'); var i = 0; var url = "http://www.ss.pku.edu.cn/index.php/newscenter/news/2391"; //初始url function fetchPage(x) { //封装了一层函数 startRequest(x); } function startRequest(x) { //采用http模块向服务器发起一次get请求 http.get(x, function (res) { var html = ''; //用来存储请求网页的整个html内容 var titles = []; res.setEncoding('utf-8'); //防止中文乱码 //监听data事件,每次取一块数据 res.on('data', function (chunk) { html += chunk; }); //监听end事件,如果整个网页内容的html都获取完毕,就执行回调函数 res.on('end', function () { var $ = cheerio.load(html); //采用cheerio模块解析html var time = $('.article-info a:first-child').next().text().trim(); var news_item = { //获取文章的标题 title: $('div.article-title a').text().trim(), //获取文章发布的时间 Time: time, //获取当前文章的url link: "http://www.ss.pku.edu.cn" + $("div.article-title a").attr('href'), //获取供稿单位 author: $('[title=供稿]').text().trim(), //i是用来判断获取了多少篇文章 i: i = i + 1, }; console.log(news_item); //打印新闻信息 var news_title = $('div.article-title a').text().trim(); savedContent($,news_title); //存储每篇文章的内容及文章标题 savedImg($,news_title); //存储每篇文章的图片及图片标题 //下一篇文章的url var nextLink="http://www.ss.pku.edu.cn" + $("li.next a").attr('href'); str1 = nextLink.split('-'); //去除掉url后面的中文 str = encodeURI(str1[0]); //这是亮点之一,通过控制I,可以控制爬取多少篇文章. if (i <= 500) { fetchPage(str); } }); }).on('error', function (err) { console.log(err); }); } //该函数的作用:在本地存储所爬取的新闻内容资源 function savedContent($, news_title) { $('.article-content p').each(function (index, item) { var x = $(this).text(); var y = x.substring(0, 2).trim(); if (y == '') { x = x + ' '; //将新闻文本内容一段一段添加到/data文件夹下,并用新闻的标题来命名文件 fs.appendFile('./data/' + news_title + '.txt', x, 'utf-8', function (err) { if (err) { console.log(err); } }); } }) } //该函数的作用:在本地存储所爬取到的图片资源 function savedImg($,news_title) { $('.article-content img').each(function (index, item) { var img_title = $(this).parent().next().text().trim(); //获取图片的标题 if(img_title.length>35||img_title==""){ img_title="Null";} var img_filename = img_title + '.jpg'; var img_src = 'http://www.ss.pku.edu.cn' + $(this).attr('src'); //获取图片的url //采用request模块,向服务器发起一次请求,获取图片资源 request.head(img_src,function(err,res,body){ if(err){ console.log(err); } }); request(img_src).pipe(fs.createWriteStream('./image/'+news_title + '---' + img_filename)); //通过流的方式,把图片写到本地/image目录下,并用新闻的标题和图片的标题作为图片的名称。 }) } fetchPage(url); //主程序开始运行