zoukankan      html  css  js  c++  java
  • 保存知乎收藏夹功能的NodeJS版本

    前两天发现知乎收藏夹中的答案正在不断减少。。看来需要保存一下了,但之前别人的方式是用chrome插件(浏览器无法自动保存本地文件)+wget前后端配合来完成这个工作的,而且还有一些缺点(比如保存的html无法更名),十分麻烦,所以打算用后端程序来抓一下网页,最终还是选择了Node来实现,是因为想借此机会学习一下Node。

    结果:好端端的异步编程被窝写成了同步编程。。这次就放同步编程的代码好了,下次再放异步的。。(而且发现在一个月前就有人用python和c#实现了一个足够好的版本。。一下就没动力了)

    废话少说,放代码。(Node的基本知识不用我说了吧)

    //自己用的小品代码,所以没有拆成多个模块,而是塞到一起了。
    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>([sS]+)</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));
    
  • 相关阅读:
    android布局
    Windows7 32/64位系统搭建Cocos2d-x及Android交叉编译环境
    第12章 文件管理
    第十章 多处理器和实时调度
    C语言实现多级反馈队列调度算法
    C++实现操作系统调度算法(FSFS,SJF,RR,多级反馈队列算法)
    多级反馈队列调度算法
    第九章 单处理器调度
    第六章 并发:死锁与饥饿
    第七章 内存管理
  • 原文地址:https://www.cnblogs.com/suprise/p/3635525.html
Copyright © 2011-2022 走看看