保存知乎收藏夹功能的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 ...
随机推荐
- [C++基础]一个比较常用的配置文件/初始化文件读取程序
在编程中,我们经常会遇到一些配置文件或初始化文件.这些文件通常后缀名为.ini或者.conf,可以直接用记事本打开.里面会存储一些程序参数,在程序中直接读取使用.例如,计算机与服务器通信,服务器的ip ...
- Sublime Text 2 使用笔记(大全呀,菜鸟必看)
下载和安装 Sublime Text2是一款开源的软件,不需要注册即可使用(虽然没有注册会有弹窗,但是基本不影响使用). 下载地址:http://www.sublimetext.com ,请自行根据系 ...
- css限制图片大小,避免页面撑爆
/*==========限制图片大小======避免页面撑暴========*/img { max-width:100%;width:expression(width>669?"100 ...
- [bzoj 1064][NOI2008]假面舞会(dfs判断环)
题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1064 分析: 如果a看到b,则a->b 那么: 1.如果图中有环,则说明这个环的 ...
- ThreadLocal模式的核心元素
首先来看ThreadLocal模式的实现机理:在JDK的早期版本中,提供了一种解决多线程并发问题的方案:java.lang.ThreadLocal类.ThreadLocal类在维护变量时,世纪使用了当 ...
- mysqldump使用方法
1.mysqldump的几种常用方法: (1)导出整个数据库(包括数据库中的数据) mysqldump -u username -p dbname > dbname.sql (2)导出数据库结构 ...
- 每天一个linux命令(40):watch命令
watch是一个非常实用的命令,基本所有的Linux发行版都带有这个小工具,如同名字一样,watch可以帮你监测一个命令的运行结果,省得你一遍遍的手动运行.在Linux下,watch是周期性的执行下个 ...
- MOTT的学习(一)
MQTT的消息体 flag 此标志设置时,客户端或服务器尝试重新publish,PUBREL,subcribe或unsubscribe消息.这适用于消息, 其中的QoS的值大于零(0),并且需要确认. ...
- ADHelper C#域用户操作(转)
using System; using System.Collections.Generic; using System.DirectoryServices; using System.Linq; u ...
- Java设计模式-观察者模式(Observer)
包括这个模式在内的接下来的四个模式,都是类和类之间的关系,不涉及到继承,学的时候应该 记得归纳,记得本文最开始的那个图.观察者模式很好理解,类似于邮件订阅和RSS订阅,当我们浏览一些博客或wiki时, ...