保存知乎收藏夾功能的NodeJS版本

前兩天發現知乎收藏夾中的答案正在不斷減小。。看來須要保存一下了,但以前別人的方式是用chrome插件(瀏覽器沒法自動保存本地文件)+wget先後端配合來完成這個工做的,並且還有一些缺點(好比保存的html沒法改名),十分麻煩,因此打算用後端程序來抓一下網頁,最終仍是選擇了Node來實現,是由於想借此機會學習一下Node。javascript

結果:好端端的異步編程被窩寫成了同步編程。。此次就放同步編程的代碼好了,下次再放異步的。。(並且發如今一個月前就有人用python和c#實現了一個足夠好的版本。。一下就沒動力了)html

廢話少說,放代碼。(Node的基本知識不用我說了吧)java

//本身用的小品代碼,因此沒有拆成多個模塊,而是塞到一塊兒了。
var http = require('http'),
    fs = require('fs'),
    path = require('path');


//本身封裝的一個建立目錄的工具函數,由於要建立的目錄的父目錄不存在時,不會像shell指令同樣連父目錄一塊建立了,而是會報錯。
//因此用try-catch,出錯的話則把目錄拆成多個部分,一步步檢查。
function myMkdir(dir) {
    var nowPath = '';
    dir = path.normalize(dir.toString());
    try{
        if (fs.existsSync(dir) !== true) {
            fs.mkdirSync(dir);
        } else {
            console.log('該目錄或文件已存在');
            return true;
        }
    } catch (e) {
        dir = path.normalize('/') === '\\'? dir.split('\\'):dir.split('/');
        while (dir.length > 0) {
            nowPath += dir.shift()+'\\';
                if (fs.existsSync(nowPath) === true && fs.statSync(nowPath).isDirectory() === false) {
                    console.log(nowPath+'處已有文件存在,請指定其餘目錄。');
                    return false;
                } else if (fs.existsSync(nowPath) === true && fs.statSync(nowPath).isDirectory() === true) {
                    continue;
                }else {
                    try {
                        fs.mkdirSync(nowPath);
                    } catch (e) {
                        console.log('建立目錄'+nowPath+'失敗,多是權限不足,請指定其餘目錄。');
                        return false;
                    }
                }

        }
    }
    console.log('建立目錄成功');
    return true;
}
//從module.paths獲取程序運行的當前目錄
function getNowPath () {
    //不一樣系統的斜槓不一樣,須要這樣處理一下。
    var slash = path.normalize('/');
    return module.paths[0].split(slash).slice(0,-1).join(slash);
}

//src,dir
//傳入兩個參數,src和dir,src是指定知乎上收藏夾的url,dir是指定保存目錄
//個人作法是,先檢查目錄dir,而後遍歷src的目錄頁得到全部文章的連接,最後再一一下載
function main(argv) {
    var waitingList = [],nowBuffer,
        slash = path.normalize('/'),
        src = argv[0],
        dir = argv[1],
        links = [],
        nowPage = 0,    //當前頁碼
        totalPage, //總頁碼
        downloading = -1,
        whitespace = "[\\x20\\t\\r\\n\\f]",
        //node不能用jQuery和DOM的API很蛋疼。。因此正則只能寫長一點。。
        rgetTotalPage = new RegExp('<span>'+whitespace+'*<a href="\\?page=(\\d+)">\\1<\\/a>'+whitespace+'*<\\/span>'+whitespace+'*<span>'+
            whitespace+'*<a href="\\?page=2">下一頁<\\/a>'+whitespace+'*<\\/span>'+whitespace+'*<\\/div>');
    var getAllLinkThisPage = function () {
        nowPage++;
        var contentTmp = [];
        var reg = /href="(\/question\/\d+\/answer\/\d+)">/g,
            match = true;

        if (nowPage <= totalPage) {
            console.log('正在獲取第'+nowPage+'頁的連接');
            http.get(src+'?page='+nowPage,function (response) {
                response.on('data',function (chunk) {
                    contentTmp.push(chunk);
                });
                response.on('end',function () {
                    console.log('第'+nowPage+'頁連接獲取完畢');

                    contentTmp = Buffer.concat(contentTmp).toString();
                    while (reg.lastIndex < contentTmp.length && match) {
                        match = reg.exec(contentTmp);
                        if (match) {
                            var tmp = {type:'html',address:'http://www.zhihu.com'+match[1],dir:dir};
                            links.push(tmp);
                        }
                    }
                    contentTmp = [];
                    getAllLinkThisPage();
                });
            });
        } else {
            console.log('連接獲取完畢,開始下載頁面,總共有'+links.length+'個頁面');
            download();
        }
    };
    var download = function () {
        downloading++;
        var rgetTitle = /<title>([\s\S]+)<\/title>/,
            match = true,
            title = '',
            fileName = '';
        if (downloading < links.length) {
            http.get(links[downloading].address,function (response) {
                console.log('開始下載第'+downloading+'個頁面');
                console.log(links[downloading].address);
                var contentTmp = [];
                response.on('data',function (chunk) {
                    contentTmp.push(chunk);
                });
                response.on('end',function () {
                    contentTmp = Buffer.concat(contentTmp).toString();
                    title = rgetTitle.exec(contentTmp)[1].replace(/[\\\/:*?"<>|]/g,'');
                    fileName = links[downloading].dir+path.normalize('/')+title +'.'+links[downloading].type;
                    fs.writeFile(fileName,contentTmp,function (err) {
                        if (err) {
                            console.log('建立'+fileName+'文件失敗,緣由:');
                            console.log(err);
                        } else {
                            console.log('已成功保存'+fileName);
                        }
                    });
                    contentTmp = [];
                    download();
                });
            });
        } else {
            console.log(links.length+'個文件已下載完畢');
        }
    };
    if (src === undefined || src.indexOf('www.zhihu.com') < 0) {
        console.log('獲取失敗!請輸入正確的知乎收藏夾網址,http://www.zhihu.com/collection/20026124');
        return false;
    }
    if (dir === undefined) {
        dir = getNowPath()+slash+'zhihu'+slash+src.split('/').slice(-1);
        console.log('沒有指定存放位置,將使用默認位置:'+dir);
    }
    //建立目錄
    if (fs.existsSync(dir) === false) {
        console.log('該目錄不存在,開始建立目錄');
        if(myMkdir(dir) === false) {
            console.log('建立目錄出錯,請看錯誤信息,若不能解決,請聯繫做者 Aeolia yiaolia@gmail.com');
            return false;
        }
    } else if (fs.existsSync(dir) === true && fs.statSync(dir).isDirectory() === false) {
        console.log('該目錄已被文件佔領,請移除該文件');
        return false;
    }
    console.log('開始鏈接'+src);
    http.get(src,function (response) {
        var content = [];
        console.log(response.statusCode);
        response.on('data',function (chunk) {
            content.push(chunk);
        });
        response.on('end',function () {
            content = Buffer.concat(content).toString();
            console.log('拿到目錄文件');
            totalPage = rgetTotalPage.exec(content.toString())[1];
            console.log(totalPage);
            getAllLinkThisPage();
        });

    })
}

main(process.argv.slice(2));
相關文章
相關標籤/搜索