背景
今年上半年,入了一个kindle paperwhite来看看电子书,挺好用的。但是在使用中发现,平时除了看一些电子书之外,也会看网页文章。更多的时候是在上下班路途中,地铁上无3g信号等恶劣环境下想看看书。所以,如果能把平时来不及看的文章转到kindle上,将会让上班路上的旅程非常愉快。:D
解决方案
先写方案,可以简单归纳为以下几点:
- 定义配置。声明mobi文件的标题、作者、文章链接
- 根据文章链接,抓取文章内容(html格式)
- 组合内容,写入一个html文件
- 使用工具kindlegen,处理html文件,最终生成mobi文件
- 拿到mobi文件之后,通过邮件的方式传到kindle即可
具体实现
定义配置
配置文件代码片段如下:
module.exports = {
dir : '20140706/',//生成mobi文件的目录
title : 'mobi_demo',//mobi文件标题
author : 'aslinwang',//mobi文件作者
urls : [//文章链接数组
'http://greengerong.github.io/blog/2013/04/14/li-yong-Travis-CI-rang-ni-di-github-xiang-mu-chi-xu-gou-jian-Node-js-wei-li/',
'http://blog.jobbole.com/63770/?from=timeline&isappinstalled=0',
'http://mp.weixin.qq.com/s?__biz=MjM5NjY5NTM0MQ==&mid=201123995&idx=1&sn=70484e70a1f6fe63f7ef86b72f358cc0&scene=2&from=timeline&isappinstalled=0#rd',
'http://www.oschina.net/translate/mistakes-avoid-responsive-web-design',
'http://jser.it/blog/2014/07/07/numbers-in-javascript/'
]
};
抓取网页内容
这里使用了readability.com的一个服务,调用其API并传入文章链接,可以获取到文章html内容。 API中token参数需要到其网站注册申请,url参数为文章链接 代码片段如下:
var parse = (function(){
var jsons = [];
var defer = q.defer();
var action = function(urls){
var url = urls.shift();
if(!url){
defer.resolve(jsons);
jsons = [];
return
}
console.log(url);
var data = {
token : config.TOKEN,
url : url
}
var req = https.request({
hostname : 'readability.com',
port : 443,
method : 'GET',
path : '/api/content/v1/parser?' + qs.stringify(data)
}, function(res){
var _chunk;
res.setEncoding('utf-8');
res.on('data', function(chunk){
_chunk = _chunk ? _chunk + chunk : chunk;
});
res.on('end', function(){
var json = JSON.parse(_chunk);
jsons.push(json);
action(urls);
});
});
req.on('error', function(e){
defer.reject('parse request error!');
});
req.end();
return defer.promise;
}
return action;
}());
组合内容为html文件
上面的步骤可以获取到各个文章的html内容,这个步骤就是简单的将这些内容组合成一个html文件。代码片段如下所示:
var makeMobi = function(info){
DATA_PATH = DATA_PATH + info.dir;
//make html 文件操作
var dest = './modules/mobi/data/' + info.dir + info.title + '.html';
var html = [
'<html>',
'<head>',
'<title><%=title%></title>',
'</head>',
'<body>',
'<%for(var i=0;i<pages.length;i++){ %>',
'<h1><%=pages[i].title%></h1>',
'<%=pages[i].content%>',
'<br /><br />',
'<% } %>',
'</body>',
'</html>'
].join('');
var medias = [];
for(var i = 0; i < info.pages.length; i++){
info.pages[i].title = util.encodeGB2312(info.pages[i].title);
info.pages[i].content = parseMedia(info.pages[i].content);
}
info.title = util.encodeGB2312(info.title);
html = util.txTpl(html, info);
html = cureHtml(html);
fs.writeFile(dest, html, function(e){
fetchMedia().done(function(){
//html -> mobi
cp.exec('kindlegen ' + dest, function(err, stdout, stderr){
console.log('kindlegen log>>>', stdout);
console.log('kindlegen err>>>', stderr);
});
});
});
};
需要注意的是,需要对内容中所含的中文进行编码,否则在kindle中阅读的时候,中文将会是乱码。
还有一点是上面的代码对图片()的处理。程序将图片从网络上拉取存在本地,然后将图片的src改成本地地址。这么做是因为在下面生成mobi文件的时候,kindlegen不能拉取网络图。
生成mobi文件
在上面的代码中,其实已经涉及到了生成mobi文件的过程,简单执行一个命令行即可。具体kindlegen的用法可以通过help了解
cp.exec('kindlegen ' + dest, function(err, stdout, stderr){
console.log('kindlegen log>>>', stdout);
console.log('kindlegen err>>>', stderr);
});
`` 拿到mobi文件之后,后面的过程就是上传到kindle中了。
使用方法
- 在modules/mobi/data目录下新建一个格式为”yyyymmdd”的目录,并编写配置文件index.js
- 输入命令:
node app.js -mobi 20140809
参考
- https://www.readability.com/developers/api/parser (readability文档)
- http://www.idpf.org/epub/20/spec/OPF_2.0.1_draft.htm (OPF格式规范)
- http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765211 (kindlegen下载地址,注册账户所在国籍必须是美帝才能下载。。)
- http://aslinwang.u.qiniudn.com/Android_Training.mobi (利用此方法制作的Android官网Training文件)
项目主页
https://github.com/aslinwang/aslin
https://github.com/aslinwang/aslin/modules/mobi (mobi制作模块)