索鸟网

  1. 首页
  2. 使用Node.js做出自己的CLI工具

使用Node.js做出自己的CLI工具


最近自己用 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,幸好有中文版的,用了allafter两种方法。all是全部事件触发emit,就会执行执行。after是在n次执行完后,才触发,nafter的第二个参数。

按理说for循环用after比较好处理,然而我拿不到for的次数,因为被封装在另一个函数中。我试了好多次都不成功。换all吧,all面临一个问题是,怎么样监听什么售后下载完,才发送给all。由于我用的是request模块的pipe方法,后面不能监听呀。eventproxy还没知道怎么用呢,两个方法都不能立马行得通,很打击人的啊。

认准一条路,脚踏实地的走下去

after试过了很多次都行不通,all又因为request后面直接使用pipe不能监听。果断选择all,至少我知道只要能监听request什么时候执行完,就可以发起all了。而after我根本就没有思路,就算这条路是捷径,我也走不了,还不如脚踏实地的focus目标。

既然request直接使用pipe不能监听,那我不直接使用不就行了。上网找了个方法,用fs.writeStreamon监听。把eventproxyemit放在oncallback里面,用一个变量来累加计算,判断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自己的命令行工具集。

相关标签: Node.js Linux

本文原创发布于慕课网 ,转载请注明出处,谢谢合作!

来源地址:http://www.imooc.com/article/19887 版权归作者所有!

相关教程

  • Node.js在CLI下的工程化体系实践

    本文作者:ivweb 程柳峰 原文出处:IVWEB社区 未经同意,禁止转载 背景: 随着开发团队规模不断发展壮大,在人员增加的同时也带来了协作成本的增加,业务项目越来越多,类型也各不相同。常见的类型有组件类、活动类、基于React+redux的业务项目、RN项目、Node.js项目等等。如果想要对每个项目进行一些规范的约束比如Git提交规范、Javascript规范简
  • Angular CLI 安装和使用

    背景介绍 关于Angular版本,Angular官方已经统一命名Angular 1.x同一为Angular JS;Angular 2.x及以上统称Angular; CLI是Command Line Interface的简写,是一种命令行接口,实现自动化开发流程,比如:ionic cli、vue cli等;它可以创建项目、添加文件以及执行一大堆开发任务,比
  • Node.js中流的使用

    流是基于事件的API,用于管理和处理数据,而且有不错的效率.借助事件和非阻塞I/O库,流模块允许在其可用的时候动态处理,在其不需要的时候释放掉. 使用流的好处 举一个读取文件的例子:使用fs.readFileSync同步读取一个文件,程序会被阻塞,所有的数据都会被读取到内存中.换用fs.readFile读取文件,程序不会被阻塞,但是所有的数据依旧会被一次
  • Node.js 命令行工具检查更新的正确姿势

    本文首发于我的博客,转载请注明出处:https://kohpoll.github.io/blo... 随着 Node.js 的“走红”,使用 Node.js 开发命令行工具越来越简单。一个成熟的命令行工具应该从一开始就要考虑好之后的版本更新如何“优雅”的告知用户。最好的方法当然是当用户在终端执行命令时,将相关信息提示给用户。 这篇文章将给出一个易用、高效
  • sed工具的使用

    sed:流式编辑器,把前一个程序的输出结果引入sed的输入,经过一系列编辑命令转换为另种格式输出命令的基本格式:sed option "script" file1 file2 ...sed option -f scriptfile file1 file2 ...其中处理的文件可以由标准输入重定向得到,也可由命令行参数传入,sed会依次处理传入的多个文件,然后逐行进行处理sed的编
  • Nodejs学习记录: 制作命令行工具

    小实例 开始编写之前需要确认的一件事情是你已经安装了Node.js。你可以在命令行中运行 which node 来确认是否已经安装,或者运行 node -v 查看 node 的版本 。如果你已经安装了node,你可以看到类似于下面的输出结果,一般情况安装了node.js 顺带npm工具自动安装了。 $ which node /d/Program File
  • Vue + Node.js + MongoDB 搭建自己个人网站!

    前言 在今年三月开学就萌生了做自己个人网站的想法,也了解到有HEXO等静态博客工具。但是作为一个想要进入前端坑的新人来讲,没有什么是比自己手动建站更有意义的事了。感谢论坛各位同学对我的帮助。 ≧▽≦y期间网站做了三次升级、应该达到了一个开源的要求。 这是源码地址,欢迎大家小星星我。(。・`ω´・) 这是我的个人网站,欢迎关注╭ b(~▽~)d 建站教程,
  • Node.js中Event_pool的使用场景

    Author: bugall Wechat: bugallF Email: 769088641@qq.com Github: https://github.com/bugall 一. 说好的单线程异步呢? 众所周知Node是单线程异步,其实这个是相对于Node这层来说是没有问题的。但是如果整体来看其实还是有个thread_pool