最近自己用 Node 写了很多的小工具,然而并不能全局使用。上网找了下答案,发现了 TJ 大神写的 Commander.js 可以很方便的制作命令行工具。于是就照着 API 把之前的 知乎专栏爬虫 给整成 CLI 工具。我把工具命名为nodc,意思是node collection
。除了知乎专栏爬虫,我还把中央天气预报加到里面。以后有用空还会加入跟多的小工具。
commander
: 命令行模块
这个模块是TJ大神封装好的模块,能快速开发命令行工具。官网有很多例子,我直接上我用到的方法。
#!/usr/bin/env node
var program = require('commander');
require('shelljs/global');
var zhihu = require("./src/zhihu.js")
var weather = require("./src/weather.js")
program
.command('crawler [zhihuId]')
.alias('cr')
.description(' 知乎专栏爬虫 ')
.option('-o ,--out <path>'," 输出位置")
.action(function(zhihuId, options){
var zhihuId = zhihuId || "leanreact";
var path = options.out || process.cwd();//当前执行路径
console.log(' 知乎专栏爬取 %s 到 %s 文件夹',zhihuId, path);
zhihu(zhihuId,path)
}).on('--help', function() {
console.log(' 举个栗子:');
console.log();
console.log(' $ nodc crawler leanreact');
console.log(' $ nodc cr leanreact -o ~/');
console.log();
});
program
.command('weather [townName]')
.alias('wt')
.description(' 天气助手 ')
.option('-d ,--detail'," 输出位置")
.action(function(townName, program){
var townName = townName || "深圳";
// var d = program.detail || false;//当前执行路径
// console.log(' 知乎专栏爬取 %s 到 %s 文件夹',townName, path);
weather(townName,program)
}).on('--help', function() {
console.log(' 举个栗子:');
console.log();
console.log(' $ nodc crawler leanreact');
console.log(' $ nodc cr leanreact -o ~/');
console.log();
});
program
.parse(process.argv);
上面是 commander 模块创建类似git一样的子命令的代码
command
:是创建子命令的方法,可以接收两个参数。接收一个参数时,可以使用 action
方法在后面发起动作。接收两个参数时,第二个参数是命令说明,后边就不能使用action
了。[zhihuId]
意思是可选参数,因为我后面在action
方法里设置了默认知乎专栏id
alias
:子命令别名
description
:命令摘要说明
option
:子命令属性。我设置了输出路径属性,接收两个参数,第二个参数为命令说明。字符串中-o
必须在--out
前面,后面<path>
是必填参数。如果option
不跟在command
后面,则作为主命令的属性。
action
:动作,顾名思义,就是发起子命令时做什么动作。传一个匿名函数做参数,前面 command 后面括号的内容可以作为参数传入。而 option 的中括号的参数需要用options.参数
来传入
on
:这里设置了help的说明
.parse(process.argv)
:没了这个代码好像不能用,这个放在所有 program 的最后,就像是 JavaScript程序的return
,放在这行代码后面的commander
模块代码都不会执行,就算只是简单打console.log
也不会执行。不过我在前面调用了zhihu(zhihuId,path)
,zhihu()
里面的代码引用并不受它影响。
关于这个模块就说这么多。更多用法可以去github看README,有中文版的。
整合 GetZhiHuZhuanLan之前写这个爬虫留下了很多问题没处理,这也是我参考zhangolve的项目的后遗症。第一个问题是,把整个爬虫分成两部分处理的:爬取下载,线下处理。第二个问题是,代码转换都成单行。由于这段时间都没空,也就搁置了。前些天看到 Node也能写命令行工具,就拿这个爬虫来试手。翻出来看,完全不能忍啊。于是找各种办法把问题处理了。
把两个分离模块合在同一个文件里
其实不写成同一个文件里也没关系的。不过为了开发方便,不用切换文件,我还是硬把两个模块的所有代码都放进去了。放进去,改了下参数名跑了一次,卧槽,线下处理的for循环居然跑在爬取下载模块的前面,怪不得之前我参考的项目是把两个文件分开来执行。
怎么办?怎么办?这问题很让人抓狂啊。
这时候一定要冷静,两个模块能分开运行,都能完成自己的任务,问题处在哪里?问题在于JavaScript的任务队列里:线下处理模块是被 for 包裹的同步运行代码,而爬取下载是一个异步的任务。如果把两个模块放一起,异步任务发起后,执行异步需要时间,而这时候,轮到for循环,它要处理下载好的json文件,可是异步下载还没完成呢,自然for里面的任务就异常了。
首次使用 eventproxy
相同了这个问题,赶紧去恶补 callback ,异步的知识,用了 async,感觉要搞很多代码,转向用朴灵大神的eventproxy
。其实这个我完全是第一次玩呀,硬着头皮上吧。
看了下 README,幸好有中文版的,用了all
和after
两种方法。all
是全部事件触发emit
,就会执行执行。after
是在n
次执行完后,才触发,n
是after
的第二个参数。
按理说for循环用after
比较好处理,然而我拿不到for的次数,因为被封装在另一个函数中。我试了好多次都不成功。换all
吧,all
面临一个问题是,怎么样监听什么售后下载完,才发送给all
。由于我用的是request
模块的pipe
方法,后面不能监听呀。eventproxy
还没知道怎么用呢,两个方法都不能立马行得通,很打击人的啊。
认准一条路,脚踏实地的走下去
after
试过了很多次都行不通,all
又因为request
后面直接使用pipe
不能监听。果断选择all
,至少我知道只要能监听request
什么时候执行完,就可以发起all
了。而after
我根本就没有思路,就算这条路是捷径,我也走不了,还不如脚踏实地的focus目标。
既然request
直接使用pipe
不能监听,那我不直接使用不就行了。上网找了个方法,用fs.writeStream
的on
监听。把eventproxy
的emit
放在on
callback里面,用一个变量来累加计算,判断for
写入次数来执行emit
。
这个脚本还是比较容易实现的,在这里谢谢吴广海兄弟,帮我优化了代码。为了显示好看一点,我使用了cli-table2
表格模块,在知乎爬虫和天气预报里都使用了Emoji。
因为我本来就没有npmjs的账号,所以不能发布在npmjs上,那怎么样全局使用呢?方法还是有的:
# 获取源码
$ git clone https://github.com/bubao/nodc
# 修改 index.js 第一行,换成自己 node 运行路径
# 项目的根目录下
$ sudo npm i -g
全部操作都在下面了:
# 查看帮助
$ nodc -h
# 知乎爬虫完整子命令
$ nodc cr [zhihuzhuanlanId] -o <path>
# 默认路径为当前文件夹下
$ nodc cr [zhihuzhuanlanId]
# 默认只爬取 learnreact 专栏
$ nodc cr
# 天气预报完整子命令
$ nodc wt [townName] -d
# 天气基本信息
$ nodc wt [townName]
# 默认深圳天气
$ nodc wt
知乎专栏爬虫
这个项目其实还有很多小 bug,code
标签转换成 markdown 时是单反引号。目前的 markdown 转换工具使用的是 h2m ,如果有更好的工具请告知我,让我能尽快完善这个小爬虫,谢谢。
中央天气预报
这个项目用了-API 提供的 api 写的天气查询,目前还不是很完善,但是已经可以用了,后续继续做些小细节上的工作。
还有很多事没做呢这是只是我nodc
的第一个小功能,我还想集成更多。
nodc
功能列表
- [x] 知乎专栏爬虫
- [x] 中央天气预报
- [ ] 结巴分词全文排序关键词
- [ ] 彩色输出
- [ ] 翻译
- [ ] 纪念日提醒
- [ ] 每日小tag
- [ ] ...
而知乎专栏爬虫还有些问题需要解决:
- [x] 文件名上加入文章发布时间,方便排序(
20170717@learnreact.md
) - [ ] 代码还很不美观,而且部分代码需要重写,虽然可以运行(用
request
代替https
) - [ ] 增加进度条,让爬虫进度更直观。
- [ ] 增加多id下载
- [ ] 输出带颜色的信息
你们可能会说,别人其实已经造好了很多轮子,比如翻译就有 ici,为什么我还要自己弄?因为别人的东西,如果出了bug ,我自己修改会很费力,或者我只能坐以待毙。而我想通过一个个小项目开源给大家一起来完善,自己享用自己的劳动成果,也是一件乐事。
我希望这个小项目能更多的人参与进来,一起DIY自己的命令行工具集。