保存知乎收藏夹功能的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 ...
随机推荐
- 对于RegExp反向引用的一点理解
置顶文章:<纯CSS打造银色MacBook Air(完整版)> 上一篇:<关于js的Array.prototype.slice.call> 作者主页:myvin 博主QQ:85 ...
- 记录我学github的路程(二)
2015-12-09 更新 1,现在,本地有了一个库,你可能会想到GitHub创建一个库,并且关联起来.这样,远程的库既可以当作备份,又可以让其他人通过该仓库来协作. 2,步骤: (1)登录GitHu ...
- Aspose.Cells 读取受保护的Excel
最近遇到一个需求,要能够读取受密码保护的Excel内容,之前都是直接读取Excel中的数据,不需要做任何其他的处理. 当Excel双击的时候,需要输入密码,在使用Aspose.Cells 组件读取 ...
- 【BZOJ1011】【HNOI2008】遥远的行星(乱搞)
1011: [HNOI2008]遥远的行星 Time Limit: 10 Sec Memory Limit: 162 MBSec Special JudgeSubmit: 1444 Solved ...
- 一头扎进EasyUI3
惯例广告一发,对于初学真,真的很有用www.java1234.com,去试试吧! 一头扎进EasyUI第11讲 .基本下拉组件 <select id="cc" style=& ...
- java数组的增删改查
import java.util.List; import java.util.ArrayList; import java.util.Set; import java.util.HashSet; p ...
- java--- Map详解
Map简介 将键映射到值的对象.一个映射不能包含重复的键:每个键最多只能映射到一个值.此接口取代 Dictionary 类,后者完全是一个抽象类,而不是一个接口. Map 接口提供三种collecti ...
- java操作excel总结---poi
前不久做过Excel的导入导出功能,其主要的难点是java如何操作Excel文档.现在就来介绍一下利用Apache的poi如何操作Excel. 1.准备工作:导入Apache POI的相关jar包,P ...
- FusionCharts的使用方法
来源于:http://www.cnblogs.com/xuhongfei/archive/2013/04/12/3016882.html 今天统计价格变化规律的时候找到的一个很好的文档,很详细 一.简 ...
- Maven 初学(一)基本概念
Pom中有三个主要元素 Groupid,artifactid,version goupid 是一个组织唯一的标识 例如 com.ibm.www artifactid 是一个工程呢ID ...