[js高手之路]Node.js+jade抓取博客所有文章生成静态html文件

这个周末,恶补了一下jade模板引擎,就为生成静态html文件,这篇文章需要知道jade以及看过我的上篇文章,我先给出他们的参考链接:

[js高手之路]Node.js模板引擎教程-jade速学与实战1-基本用法

[js高手之路]Node.js模板引擎教程-jade速学与实战2-流程控制,转义与非转义

[js高手之路]Node.js模板引擎教程-jade速学与实战3-mixin

[js高手之路]Node.js模板引擎教程-jade速学与实战4-模板引用,继承,插件使用

[js高手之路]Node.js实现简易的爬虫-抓取博客所有文章列表信息

在上面分享的这篇文章中,我抓取了博客的所有文章列表. 并没有采集入库,也没有做别的处理。这篇文章,我们就把上文中采集到的所有文章列表的信息整理一下,开始采集文章并且生成静态html文件了.先看下我的采集效果,我的博客目前77篇文章,1分钟不到就全部采集生成完毕了,这里我截了部分的图片,文件名用文章的id生成的,生成的文章,我写了一个简单的静态模板,所有的文章都是根据这个模板生成的.

项目结构:

 

 

 好了,接下来,我们就来讲解下,这篇文章主要实现的功能:

1,抓取文章,主要抓取文章的标题,内容,超链接,文章id(用于生成静态html文件)

2,根据jade模板生成html文件

一、抓取文章如何实现?

非常简单,跟上文抓取文章列表的实现差不多

 1 function crawlerArc( url ){
 2     var html = '';
 3     var str = '';
 4     var arcDetail = {};
 5     http.get(url, function (res) {
 6         res.on('data', function (chunk) {
 7             html += chunk;
 8         });
 9         res.on('end', function () {
10             arcDetail = filterArticle( html );
11             str = jade.renderFile('./views/layout.jade', arcDetail );
12             fs.writeFile( './html/' + arcDetail['id'] + '.html', str, function( err ){
13                 if( err ) {
14                     console.log( err );
15                 }
16                 console.log( 'success:' + url );
17                 if ( aUrl.length ) crawlerArc( aUrl.shift() );
18             } );
19         });
20     });
21 }

参数url就是文章的地址,把文章的内容抓取完毕之后,调用filterArticle( html ) 过滤出需要的文章信息(id, 标题,超链接,内容),然后用jade的renderFile这个api,实现模板内容的替换,

模板内容替换完之后,肯定就需要生成html文件了, 所以用writeFile写入文件,写入文件时候,用id作为html文件名称。这就是生成一篇静态html文件的实现,

接下来就是循环生成静态html文件了, 就是下面这行:

if ( aUrl.length ) crawlerArc( aUrl.shift() );
 
aUrl保存的是我的博客所有文章的url, 每次采集完一篇文章之后,就把当前文章的url删除,让下一篇文章的url出来,继续采集
 

完整的实现代码server.js:

  1 var fs = require( 'fs' );
  2 var http = require( 'http' );
  3 var cheerio = require( 'cheerio' );
  4 var jade = require( 'jade' );
  5 
  6 var aList = [];
  7 var aUrl = [];
  8 
  9 function filterArticle(html) {
 10     var $ = cheerio.load( html );
 11     var arcDetail = {};
 12     var title = $( "#cb_post_title_url" ).text();
 13     var href = $( "#cb_post_title_url" ).attr( "href" );
 14     var re = /\/(\d+)\.html/;
 15     var id = href.match( re )[1];
 16     var body = $( "#cnblogs_post_body" ).html();
 17     return {
 18         id : id,
 19         title : title,
 20         href : href,
 21         body : body
 22     };
 23 }
 24 
 25 function crawlerArc( url ){
 26     var html = '';
 27     var str = '';
 28     var arcDetail = {};
 29     http.get(url, function (res) {
 30         res.on('data', function (chunk) {
 31             html += chunk;
 32         });
 33         res.on('end', function () {
 34             arcDetail = filterArticle( html );
 35             str = jade.renderFile('./views/layout.jade', arcDetail );
 36             fs.writeFile( './html/' + arcDetail['id'] + '.html', str, function( err ){
 37                 if( err ) {
 38                     console.log( err );
 39                 }
 40                 console.log( 'success:' + url );
 41                 if ( aUrl.length ) crawlerArc( aUrl.shift() );
 42             } );
 43         });
 44     });
 45 }
 46 
 47 function filterHtml(html) {
 48     var $ = cheerio.load(html);
 49     var arcList = [];
 50     var aPost = $("#content").find(".post-list-item");
 51     aPost.each(function () {
 52         var ele = $(this);
 53         var title = ele.find("h2 a").text();
 54         var url = ele.find("h2 a").attr("href");
 55         ele.find(".c_b_p_desc a").remove();
 56         var entry = ele.find(".c_b_p_desc").text();
 57         ele.find("small a").remove();
 58         var listTime = ele.find("small").text();
 59         var re = /\d{4}-\d{2}-\d{2}\s*\d{2}[:]\d{2}/;
 60         listTime = listTime.match(re)[0];
 61 
 62         arcList.push({
 63             title: title,
 64             url: url,
 65             entry: entry,
 66             listTime: listTime
 67         });
 68     });
 69     return arcList;
 70 }
 71 
 72 function nextPage( html ){
 73     var $ = cheerio.load(html);
 74     var nextUrl = $("#pager a:last-child").attr('href');
 75     if ( !nextUrl ) return getArcUrl( aList );
 76     var curPage = $("#pager .current").text();
 77     if( !curPage ) curPage = 1;
 78     var nextPage = nextUrl.substring( nextUrl.indexOf( '=' ) + 1 );
 79     if ( curPage < nextPage ) crawler( nextUrl );
 80 }
 81 
 82 function crawler(url) {
 83     http.get(url, function (res) {
 84         var html = '';
 85         res.on('data', function (chunk) {
 86             html += chunk;
 87         });
 88         res.on('end', function () {
 89             aList.push( filterHtml(html) );
 90             nextPage( html );
 91         });
 92     });
 93 }
 94 
 95 function getArcUrl( arcList ){
 96     for( var key in arcList ){
 97         for( var k in arcList[key] ){
 98             aUrl.push( arcList[key][k]['url'] );
 99         }
100     }
101     crawlerArc( aUrl.shift() );
102 }
103 
104 var url = 'http://www.cnblogs.com/ghostwu/';
105 crawler( url );

layout.jade文件:

doctype html
html
    head
        meta(charset='utf-8')
        title jade+node.js express
        link(rel="stylesheet", href='./css/bower_components/bootstrap/dist/css/bootstrap.min.css')
    body
        block header
            div.container
                div.well.well-lg
                    h3 ghostwu的博客
                    p js高手之路
        block container
            div.container
                h3
                    a(href="#{href}") !{title}
                p !{body}
        block footer
            div.container
                footer 版权所有 - by ghostwu

后续的打算:

1,采用mongodb入库

2,支持断点采集

3,采集图片

4,采集小说

等等....

 

posted @ 2017-09-18 21:55  ghostwu  阅读(1449)  评论(0编辑  收藏  举报
Copyright ©2017 ghostwu