设为首页 收藏本站
查看: 1063|回复: 0

[经验分享] nodejs爬取博客园的博文

[复制链接]

尚未签到

发表于 2017-2-23 07:50:59 | 显示全部楼层 |阅读模式
  其实写这篇文章,我是很忐忑的,因为爬取的内容就是博客园的,万一哪个顽皮的小伙伴拿去干坏事,我岂不成共犯了?
  
  好了,进入主题。
  首先,爬虫需要用到的模块有:
  express
  ejs
  superagent (nodejs里一个非常方便的客户端请求代理模块)
  cheerio (nodejs版的jQuery)
  前台布局使用bootstrap
  分页插件使用 twbsPagination.js
  完整的爬虫代码,在我的github中可以下载。主要的逻辑代码在 router.js 中。

1. 爬取某个栏目第1页的数据
  分析过程:
  打开博客园的主页: http://www.cnblogs.com/
  左侧导航栏里显示了所有栏目的分类信息,可以在开发者工具中获取查看这些信息.
DSC0000.png

  每个栏目的URL也很有规律,都是 www.cnblogs.com/cate/栏目名称。 根据这个URL就可以爬取某个栏目第1页的博文了~

  下面贴出代码:
  app.js (入口文件)



// 载入模块
var express = require('express');
var app = express();
var router = require('./router/router');

// 设置模板引擎
app.set('view engine', 'ejs');

// 静态资源中间件
app.use(express.static('./public'));

// 博客园
app.get('/cnblogs', router.cnblogs);
// 栏目
app.get('/cnblogs/cate/:cate/', router.cnblogs_cate);

app.listen(1314, function(err){
     if(err) console.log('1314端口被占用');
});
  router.js



var request = require('superagent');
var cheerio = require('cheerio');
// 栏目
var cate = [
'java', 'cpp', 'php', 'delphi', 'python', 'ruby',
'web', 'javascript', 'jquery', 'html5'
];
// 显示页面
exports.cnblogs = function(req, res){
res.render('cnblogs', {
cate: cate
});
};
// 爬取栏目数据
exports.cnblogs_cate = function(req, res){
// 栏目
var cate = req.params['cate'];
request
.get('http://www.cnblogs.com/cate/' + cate)
.end(function(err, sres){
var $ = cheerio.load(sres.text);
var article = [];
$('.titlelnk').each(function(index, ele){
var ele = $(ele);
var href = ele.attr('href'); // 博客链接
var title = ele.text();      // 博客内容
            article.push({
href: href,
title: title
});            
});
res.json({
title: cate,
cnblogs: article
});
});
};
  cnblogs.ejs
  只贴出核心代码



<div class="col-lg-6">
           <select class="form-control" id="cate">
             <option value="0">请选择分类</option>
             <% for(var i=0; i<cate.length; i++){ %>
               <option value="<%= cate%>"><%= cate%></option>
             <% } %>
           </select>
</div>
  JS模板



    <script type="text/template" id="cnblogs">
<ul class="list-group">
<li class="list-group-item">
<a href="{{= href}}" target="_blank">{{= title}}</a>
</ul>
</script>
  Ajax请求



$('#cate').on('change', function(){
var cate = $(this).val();
if(cate == 0) return;
$('.artic').html('');
$.ajax({
url: '/cnblogs/cate/' + cate,
type: 'GET',
dataType: 'json',
success: function(data){
var cnblogs = data.cnblogs;
for(var i=0; i<cnblogs.length; i++){
var compiled = _.template($('#cnblogs').html());
var art = compiled(cnblogs);
$('.artic').append(art);
}
}
});
});
  输入: http://localhost:1314/cnblogs/  ,可以看到, 成功获取javascript下第1页数据。
DSC0001.png


2. 分页功能
  以 http://www.cnblogs.com/cate/javascript/ 为例:
  首先,分页的数据是Ajax调用后端接口返回的。

  chrome的开发者工具中,可以看到,分页时,会向服务器发送两个请求,
  PostList.aspx 请求具体某页的数据.
  load.aspx 返回分页字符串.

   DSC0002.png
  我们重点分析 PostList.aspx 这个接口:
DSC0003.png

  可以发现 请求方式是POST。
  问题的重点是POST请求的数据是如何组装的?
  分析源码,发现每个分页字符串都绑定了一个事件 -- aggSite.loadCategoryPostList()
   DSC0004.png
  查看页面源码,发现这个函数定义在 aggsite.js 文件里.
   DSC0005.png
  也就是下面这个函数.
   DSC0006.png
  重点是这行代码, 使用Ajax向后端发送请求.



this.loadPostList("/mvc/AggSite/" + aggSiteModel.ItemListActionName + ".aspx").
  分析loadPostList 函数,可以发现POST的数据是变量aggSiteModel的值.
   DSC0007.png
  而 aggSiteModel 在页面中的定义:

   DSC0008.png
  至此前端的分析告一段落。 我们要做的,就是使用nodejs,模拟浏览器发送请求。
  router.js



exports.cate_page = function(req, res){

     var cate = req.query.cate;
     var page = req.query.page;

     var url = 'http://www.cnblogs.com/cate/' + cate;

     request
     .get(url)
     .end(function(err, sres){

         // 构造POST请求的参数
         var $ = cheerio.load(sres.text);
         var post_data_str = $('#pager_bottom').prev().html().trim();
         var post_data_obj = JSON.parse(post_data_str.slice(post_data_str.indexOf('=')+2, -1));   

         // 分页接口
         var page_url = 'http://www.cnblogs.com/mvc/AggSite/PostList.aspx';
         // 修改当前页
         post_data_obj.PageIndex = page;

         request
         .post(page_url)
         .set('origin', 'http://www.cnblogs.com') // 伪造来源
         .set('referer', 'http://www.cnblogs.com/cate/'+cate+'/') // 伪造referer
         .send(post_data_obj) // POST数据
         .end(function(err, ssres){
             var article = [];
             var $$ = cheerio.load(ssres.text);
             $$('.titlelnk').each(function(index, ele){
                 var ele = $$(ele);
                 var href = ele.attr('href');
                 var title = ele.text();
                 article.push({
                     href: href,
                     title: title
                 });            
             });
             res.json({
                 title: cate,
                 cnblogs: article
             });
         });   
     });
};
  cate.ejs 分页代码



$('.pagination').twbsPagination({
   totalPages: 20, // 默认显示20页
   startPage: 1,
   visiblePages: 5,
   initiateStartPageClick: false,
   first: '首页',
   prev: '上一页',
   next: '下一页',
   last: '尾页',
   onPageClick: function(evt, page){
     $.ajax({
       url: '/cnblogs/cate_page?cate=' + cate + '&page=' + page,
       type: 'GET',
       dataType: 'json',
       success: function(data){
         $('.artic').html('');
         var cnblogs = data.cnblogs;
          for(var i=0; i<cnblogs.length; i++){
            var compiled = _.template($('#cnblogs').html());
            var art = compiled(cnblogs);
            $('.artic').append(art);
          }
       }
     });
   }
});
  输入:http://localhost:1314/cnblogs/cate,可以看到:
  javascript栏目第1页数据
DSC0009.png

  第2页数据
DSC00010.png


后话
  至此,一个简单的爬虫就完成了。  其实爬虫本身并不难,难点在于分析页面结构,和一些业务逻辑的处理。
  完整的代码,我已经放在github上,欢迎starn(☆▽☆)。
  由于是第一次写技术类的博客,文笔有限,才学疏浅,若有不正确的地方,欢迎广大博友指正。
  参考资料:
  《SuperAgent中文使用文档》
  《通读cheerio API》

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-345851-1-1.html 上篇帖子: nodejs+express+mysql 增删改查 下篇帖子: 利用nodejs实现登录并转码视频(原创)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表