Node.js 爬取语文备课大师课件

代码目录结构如下:


目录.png

bin/downloadfile.js:


var fs = require('fs');
var request = require('request');
// var async = require("async");
var exec = require('child_process').exec;
var cheerio = require('cheerio');
var config = require('../conf/config');

//加载网页解析库
var Classparse = require("../lib/classparse");

var url = config["downloadSrc"][0];
var dst = config["downloadDir"][0];
var Classparse = new Classparse(url);

//创建目的目录
if (mkdir(dst)) {
    return;
}

console.log("开启帕尼尼计划...向语文备课大师进军!");

//先获取目录列表
Classparse.getClassCatalogList().then(function(links) {
    var newDir = '';

    //根据每一个目录,获取对应下的所有下载连接
    for (var i = 0, len = links.length; i < len; i++) {

        (function(i) {
            if (i != 40) {
                return;
            }
            Classparse.getDownloadlinkArray(links[i]).then(function(downlist) {
                newDir = dst + '/' + i + '、' + downlist[0].dirTitle;
                mkdir(newDir);
                for (var index = 0; index < downlist.length; index++) {

                    Classparse.superagentDown(downlist[index].href, newDir, downlist[index].title);
                }
            });
        })(i);
    }

}).catch(function(e) {
    if (e) console.log(e);
});


//自动创建目的下载目录
function mkdir(dst) {
    if (dst) {
        var cmd = "sh -x mkdir.sh " + dst;
        var out = exec(cmd);
        out.on("exit", function(code) {
            if (code == 0) {
                console.log("mkdir " + dst + " sucess.");
            }
        });
        return 0;
    } else {
        console.error("dst目录为空!");
        return 1;
    }
}

bin/mkdir.sh :

#!/bin/bash
dst=$1

if [ "${dst}" == "" ];then
  exit -1
fi

if [ ! -e ${dst} ];then
  mkdir -p ${dst}
  ret=$?
else 
  ret=1
fi

exit ${ret}

conf/config.js :

var conf = {
    downloadSrc: [
        "http://www.xiexingcun.com/xy8/List/List_992.html",
        "http://data.xiexingcun.com/G/List/List_7380.htm"
    ],
    downloadDir: [
        "../resultClass/class"
    ]
};

module.exports = conf;

lib/classpare.js :

var request = require('request');
var cheerio = require('cheerio');
var exec = require('child_process').exec;
var iconv = require('iconv-lite');
var fs = require('fs');
var superagent = require('superagent');

var Classparse = function(url){
  this.url = url;
  this.trEles = ".left_tdbg1 td p:nth-child(1) a";
  this.downlistTreeEles = ".main_tdbgall .listA";

};

/* dec: 首先访问首页,抓取首页中的目录
 * param: this.url - 首页请求的地址
 * return: links - 子页面的链接数组
 * */
Classparse.prototype.getClassCatalogList = function(){
    var _this = this;
    return new Promise(function(resolve, reject){
        request.get({url:_this.url,encoding:null},function(e, r, html){
            //设置编码方式
            html = iconv.decode(html, 'gb2312');
            //如果请求到了首页的模板
            if (!e && r.statusCode === 200) {
                var $ = cheerio.load(html,{decodeEntities: false}),
                    treeDom = $(_this.trEles),
                    links = [],
                    href = '',
                    title = '';
                treeDom.each(function(index, item){
                    if (index > 2) {
                        href = $(item).attr('href').replace(/[ ]/g, '')
                                                   .replace(/[\r\n]/g, '');
                        title = $(item).text().replace(/[ ]/g, '')
                                              .replace(/[\r\n]/g, '');
                        links.push({
                            'href': href,
                            'title': title
                        })
                    }
                });
                resolve(links);
            }else {
                console.error("Error: " + e);
                reject(e);
            }
        });
    })
}

/* dec: 根据目录项(也就是课程名称)获取该课程下的所有课件文档URL
 * param: this.url - 首页请求的地址
 * return: links - 子页面的链接数组
 * */
Classparse.prototype.getDownloadlinkArray = function(item){
    var _this = this;
    return new Promise(function(resolve, reject){
        request.get({url: item.href, encoding:null}, function(e, r, html){
            //设置编码方式
            html = iconv.decode(html, 'gb2312');
            if (!e && r.statusCode === 200) {
                var $ = cheerio.load(html,{decodeEntities: false}),
                    treeDom = $(_this.downlistTreeEles),
                    links = [],
                    href = '',
                    title = '';

                console.log(item.title);
                treeDom.each(function(index, childitem){
                    //现在拿到的是一个一个的tr,tr里面才有a标签
                    href = $(childitem).attr('href').replace(/[ \r\n]/g, '');
                    title = $(childitem).text().replace(/[ ( )\r\n]/g, '');

                    //首先要判断是不是以/开头的
                    //因为有一些标签是http://www.xiexingcun.com/centre.html这样过来的
                    //拿到的url还要再剔除:例如拿到/D/HTML/98877.htm,要取出 D 和 98877
                    // 然后拼成一个新的URL可以提供下载的:
                    //http://data.xiexingcun.com/D/abShowSoftDown.asp?UrlID=1&SoftID=98877
                    if (/^\//.test(href)) {
                        href = 'http://data.xiexingcun.com/' +  href.split('/')[1] + '/' + 'abShowSoftDown.asp?UrlID=1&SoftID=' + href.split('/')[3].split('.')[0];
                        // console.log(href);
                        // console.log(title);
                        links.push({
                            'dirTitle': item.title,
                            'href': href,
                            'title': title
                        })
                    }
                });
                // console.log(links);

                resolve(links);
            }else {
                console.error("Error: " + e);
                reject(e);
            }
        });
    });
}

/*
 *  request
 * In: link - 下载链接,saveDir - 保存目录,name - 保存文件名
 * Out: null
 * */
Classparse.prototype.testdown = function(link, saveDir, name){
    var cmDir = saveDir + "/" + name + '.zip';
    var type = '';
    var ip = this.getRandomNum(1, 254) + '.' + this.getRandomNum(1, 254) + '.' + this.getRandomNum(1, 254);
    var stream = fs.createWriteStream(cmDir);
    request(link).pipe(stream);
}

/*
 *  superagent
 * In: link - 下载链接,saveDir - 保存目录,name - 保存文件名
 * Out: null
 * */
Classparse.prototype.superagentDown = function(link, saveDir, name){
    var cmDir = saveDir + "/" + name,
        type = '',
        ip = this.getRandomNum(1, 254) + '.' + this.getRandomNum(1, 254) + '.' + this.getRandomNum(1, 254);

    superagent
          .get(link)
          .set('X-Forwarded-For',ip)
          .end(function(err, sres){
              if (!sres) {
                  return;
              }
            //   console.log(sres.headers['content-type']);
              if (sres.headers['content-type'] === 'application/x-zip-compressed') {
                  type = '.zip';
              }else if(sres.headers['content-disposition']){
                  type = '.' + sres.headers['content-disposition'].split('.')[1];
              }else {
                  type = '.rar';
              }
              //获得文件类型后,进行pipe管子数据传输
              var stream = fs.createWriteStream(cmDir + type);
              superagent(link).set('X-Forwarded-For',ip).pipe(stream);
              console.log("下载文件: #" + name + '#  成功!');
          });
}

/*
 *  利用exec方法下载
 * In: link - 下载链接,saveDir - 保存目录,name - 保存文件名
 * Out: null
 * */
Classparse.prototype.download = function(link, saveDir, name){
    // var cmd = "curl '" + link + "' -o " + saveDir + "/" + name + '';
    var ip = this.getRandomNum(1, 254) + '.' + this.getRandomNum(1, 254) + '.' + this.getRandomNum(1, 254);
    var cmd = "curl -H 'X-Forwarded-For:" + ip + "' -o '" + saveDir + "/" + name + ".doc' '" + link + "'" ;
    console.log(cmd);

    exec(cmd, function(e,stdout,stderr){
        if (!e) {
            console.log("下载文件: #" + name + '#  成功!');
        }else {
            console.log("download err: " + e);
        }

    });
};

//获取范围内的随机数
Classparse.prototype.getRandomNum = function(min, max){
    return Math.floor(min + Math.random() * (max - min));
};

module.exports = Classparse;

lib/common.js :(暂可不用)

var exec = require('child_process').exec;

//继承封装函数
function extend(Child,Parent){
  var F = function(){};
  F.prototype = Parent.prototype;
  Child.prototype = new F();
  Child.constructor = Child;
  Child.uber = Parent.prototype;
}

//CommonParser: 解析的公共模板类定义
var CommonParser = function(url){
  this.url = url;            //由前缀+搜索词构成
};

//获取匹配的搜索结果信息
CommonParser.prototype.getMatchResultInfo = function(){
  //具体实例实现逻辑
};


//详情页面获取下载链接
CommonParser.prototype.getLink = function(){
  //实例实现
};

//下载文件
CommonParser.prototype.download = function(link,dst,name){
  var cmd = "wget " + link + " -O " + dst + "/" + name;
  console.log(cmd);
  exec(cmd,function(e){
    if(e)console.error("Error: " + e);
  });
};

exports.extend = extend;
exports.CommonParser = CommonParser;
exports.exec = exec;

//运行代码:
node downloadfile

//下载后的文件在class这个目录中
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容