保存知乎收藏夹功能的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>([\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));
保存知乎收藏夹功能的NodeJS版本的更多相关文章
- 基于Metronic的Bootstrap开发框架经验总结(12)--页面链接收藏夹功能的实现
在一个系统里面,往往有很多菜单项目,每个菜单项对应一个页面,一般用户只需要用到一些常用的功能,如果每次都需要去各个层次的菜单里面去找对应的功能,那确实有点繁琐.特别是在菜单繁多,而客户又对系统整体不熟 ...
- 基于Metronic的Bootstrap开发框架经验总结(13)--页面链接收藏夹功能的实现2(利用Sortable进行拖动排序)
在上篇随笔<基于Metronic的Bootstrap开发框架经验总结(12)--页面链接收藏夹功能的实现>上,我介绍了链接收藏夹功能的实现,以及对收藏记录的排序处理.该篇随笔主要使用功能按 ...
- JQUERY 实现加入收藏夹功能
关于"加入收藏"的代码,很多人都不会重视,一般情况是随便在网上搜一个代码放在页面里就草草了事了.可是都没有做到主流浏览器的兼容.下面分享一段使用 jQuery 实现加入收藏夹的功能 ...
- “添加到收藏夹”功能(share)
以下分享自: 如何给网站增加“添加到收藏夹” 给网站添加“添加到收藏夹”理论上应该是很简单的事情,但是受到各种浏览器和操作系统的不一致的问题,使得这个问题异常的繁琐啊. 下面是梳理的一些资料,仅供参考 ...
- js_加入收藏夹功能
<script type="text/javascript">function addToFavorite(obj) { var url = "http ...
- microsoft help viewer 收藏夹功能
平时重装系统比较多,重装后,microsoft help viewer 2.0里面的收藏就丢失了,要恢复以前的收藏,可以直接在C:\Users\ZR\AppData\Local\Microsoft\H ...
- 基于CefSharp开发浏览器(八)浏览器收藏夹栏
一.前言 上一篇文章 基于CefSharp开发(七)浏览器收藏夹菜单 简单实现了部分收藏夹功能 如(添加文件夹.添加收藏.删除.右键菜单部分功能) 后续代码中对MTreeViewItem进行了扩展,增 ...
- python scrapy爬取知乎问题和收藏夹下所有答案的内容和图片
上文介绍了爬取知乎问题信息的整个过程,这里介绍下爬取问题下所有答案的内容和图片,大致过程相同,部分核心代码不同. 爬取一个问题的所有内容流程大致如下: 一个问题url 请求url,获取问题下的答案个数 ...
- Django Web开发【3】创建网络收藏夹
这一节我们将继续一个创建网络收藏夹应用,并学习视图.模型以及模板的处理过程. Django是一个MVC开发框架,但是它的控制器对应的为view,而视图对应为模板(template),模型对应model ...
随机推荐
- Linux基础与Linux下C语言编程基础
Linux基础 1 Linux命令 如果使用GUI,Linux和Windows没有什么区别.Linux学习应用的一个特点是通过命令行进行使用. 登录Linux后,我们就可以在#或$符后面去输入命令,有 ...
- 几种Boost算法的比较(Discrete AdaBoost, Real AdaBoost, LogitBoost, Gentle Adaboost)
关于boost算法 boost算法是基于PAC学习理论(probably approximately correct)而建立的一套集成学习算法(ensemble learning).其根本思想在于通过 ...
- gulp初体验记录(简介、插件开发介绍)
目前用的业界比较知名的三个前端构建工具:grunt.gulp.fis,自己此前一直都是只在用grunt,fis看过一点,gulp则一直都没注意过,直到最近发现好像用的人越来越多,所以今天也就抽了点时间 ...
- 第三十五课:Ajax详解
一个完整的Ajax请求: var xhr = new (self.XMLHttpRequest || ActiveXObject)("Microsoft.XMLHTTP"); ...
- ipvsadm参数详解(常用命令)
[root@localhost ipvsadm]# ipvsadm -h ipvsadm v1.24 2005/12/10 (compiled with popt and IPVS v1.2.1) U ...
- “耐撕”团队 2016.03.24 站立会议
时间: 2016.03.22 17:00-17:30 18:30-19:00 成员: Z 郑蕊 * 组长 (博客:http://www.cnblogs.com/zhengrui0452/), ...
- 【OpenCV入门教程之一】 安装OpenCV:OpenCV 3.0 +VS 2013 开发环境配置
图片太多,具体过程参照: [OpenCV入门教程之一] 安装OpenCV:OpenCV 3.0.OpenCV 2.4.8.OpenCV 2.4.9 +VS 开发环境配置 说下我这边的设置: 选择deb ...
- Sublime Text 3 绝对神器
距第一篇的开箱水文,已经有4个月的时间了,但因为懒,就没有下文了.终于,今天,我觉得写一篇准技术文章了. 忘记了是怎么开始用的ST,应该是在网上看到别人推荐才用到吧,用了有半年了.在windows下是 ...
- Cas_个人理解
分为三个部分: 1.Cas服务器(用于验证用户是否正确) 1.用户信息存在服务端,其它客户端应用程序修改用户信息后需要同步到服务端 2.用户信息一般存储在服务端的数据 ...
- 【前端学习】sublime开启vim模式
学习目标:在sublime下开启vim模式,了解基本vim的编辑快捷键. 下载安装Sublime Text 3 :http://www.sublimetext.com/3 Vim/Vi: Vim/Vi ...