nodejs的基本学习(三)npm与一些内置模块

前言:

承接前面的内容我们来继续了解nodejs

 

 

 

 

 


NPM:

NPM是随同NodeJS一起安装的包管理工具,能解决NodeJS代码部署上的很多问题,常见的使用场景有以下几种:

  • 允许用户从NPM服务器下载别人编写的第三方包到本地使用。
  • 允许用户从NPM服务器下载并安装别人编写的命令行程序到本地使用。
  • 允许用户将自己编写的包或命令行程序上传到NPM服务器供别人使用。

由于新版的nodejs已经集成了npm,所以之前npm也一并安装好了。同样可以通过输入 “npm -v” 来测试是否成功安装,我们可以直接在终端用npm这个命令。

npm -v  //查看本地npm版本
npm install npm -g  //升级npm版本

如果要安装什么模块直接这样使用即可:

npm install <Module Name>

安装好之后,包就放在了工程目录下的 node_modules 目录中,因此在代码中只需要通过 require(‘包名’) 的方式就好,无需指定第三方包路径。

但是这样的安装仅对这个项目有效,这就是本地安装。

如果加上参数g(意为global),则为全局安装

npm install -g <Module Name>

之后就可以在终端将它作为可执行文件使用

如果出现以下错误:

npm err! Error: connect ECONNREFUSED 127.0.0.1:8087 

解决办法为:

$ npm config set proxy null

NPM安装包是去访问一个国外的npm服务器,大家如果觉得慢可以切换一下源到这个淘宝NPM镜像

npm uninstall <Module Name>

 

 

补充:

安装淘宝NPM后如果出现以下报错:

cnpm : 无法加载文件 C:\Users\hp\AppData\Roaming\npm\cnpm.ps1,因为在此系统上禁止运行脚本。有关详细信息,请参阅 https:/go.microsoft.com/fwlink/?LinkID=135170 中的  
about_Execution_Policies。
所在位置 行:1 字符: 1
 cnpm install amfe-flexible
+ ~~~~
    + CategoryInfo          : SecurityError: (:) [],PSSecurityException
    + FullyQualifiedErrorId : UnauthorizedAccess

解决方法:

解决方法:
1.以管理员身份运行power shell
2.输入set-ExecutionPolicy RemoteSigned
然后输入A 回车

 


package.json:

每个项目的根目录下面,一般都有一个package.json文件,定义了这个项目所需要的各种模块,以及项目的配置信息(比如名称、版本、许可证等元数据)。npm install命令根据这个配置文件,自动下载所需的模块,也就是配置项目所需的运行和开发环境。

一般我们写项目的时候,会先用 npm init 初始化这个项目,在初始化的过程中,我们就会定义各种关于项目的信息

定义完信息之后,看向左边就会发现生成了以个package.json文件

{
  "name": "hellonode",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "dependencies": {      //记录了所有安装包的一些信息
    "express": "^4.17.1"
  },
  "devDependencies": {},  //开发环境
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node server.js"
  },
  "author": "",
  "license": "ISC"
}

在终端运行 npm run start 就会运行start后面的server.js脚本,就是依据该文件的”scripts”,”scripts”里定义这个项目的入口文件

而使用npm install 他就会自动匹配package.json文件,按照dependencies等内容里的配置自动安装需要的包


nodemon:

Nodemon是一个使用工具,它将会见监视源文件中任何的更改并自动重启服务器。Nodemon不会对你的代码产生额外的更改,它只是node命令的替代品。因为当你修改源文件后,如果你用的是原来的node 则必须手动重启 你的更改才会有效。但是如果用的是nodemon,则你不需要手动操作,它会检测你的代码改动自动重启。

安装:

全局安装nodemon

npm install -g nodemon

安装完成以后,就不用再用node执行文件了,改用nodemon即可

 


内置模块:

这里来简单介绍两个nodejs的内置模块,内置模块请参考官方文档

Query String:

query:询问,问号(在这里是指url中?后面的键值)

 

参数转换:

在上一部分内容中,我们简单地过了一下关于如何得到get请求的参数等,但是那样拿到的只是一个query字符串,那要怎么从字符串中拿出键值呢?现在我们来正经学习一下Query String这个内置模块

文档——nodejsAPI文档

Application Programming Interface,应用程序编程接口

 

如下示例:

const qs=require('querystring')
#典型的query字符串
 let string='name=xiaoming&score=59&sex=1'
 let obj=qs.parse(string)
 //将query字符串变成query对象
 console.log(obj)

输出:

{ name: 'xiaoming', score: '59', sex: '1' }

很简单就转化完成了

上面的let和const与之前定义变量用的var有什么不同呢?

  • var:定义的变量可以修改,如果不初始化会输出undefined,不会报错
  • const:定义的变量不可以修改,而且必须初始化
  • let:块级作用域,函数内部使用let定义后,对函数外部无影响(局部变量)

如果要反着来,讲一个object对象转换成字符串(用=和&连接)

 const qs=require('querystring')
//这是一个object对象
 let obj={
     name:'xiaoming',
     score: '59',
     sex: '1' 
 }
 let string=qs.stringify(obj)
 console.log(string)

如果不想以=、&连接,给stringify改变参数即可

 url编解码(编码不是加密):

编码:

url百分比编码

let string='w=你好&foo=bar'
let result=qs.escape(string)
console.log(result)

输出:

w%3D%E4%BD%A0%E5%A5%BD%26foo%3Dbar

解码:

url百分比解码

let escape='w%3D%E4%BD%A0%E5%A5%BD%26foo%3Dbar'
console.log(qs.unescape(escape))

输出:

w=你好&foo=bar

URL模块:

基本转换:

url模块,根据一个url解析称为Object对象

const url=require('url')
let urlString='http://47.85.56.1:4055/sad/picture/hehe?name=xiaoming&sex=2'
let urlObj=url.parse(urlString)
console.log(urlObj)

输出:

Url {
  protocol: 'http:',
  slashes: true,
  auth: null,
  host: '47.85.56.1:4055',
  port: '4055',
  hostname: '47.85.56.1',
  hash: null,
  search: '?name=xiaoming&sex=2',
  query: 'name=xiaoming&sex=2',
  pathname: '/sad/picture/hehe',
  path: '/sad/picture/hehe?name=xiaoming&sex=2',
  href: 'http://47.85.56.1:4055/sad/picture/hehe?name=xiaoming&sex=2'
}

如果想要通过obj对象转成url字符串:

const url=require('url')

let obj={
    protocol: 'http:', 
    slashes: true, 
    auth: null, 
    host: '47.85.56.1:4055',
    port: '4055', 
    hostname: '47.85.56.1', 
    hash: null, 
    search: '?name=xiaoming&sex=2', 
    query: 'name=xiaoming&sex=2', 
    pathname: '/sad/picture/hehe', 
    path: '/sad/picture/hehe?name=xiaoming&sex=2', 
    href: 'http://47.85.56.1:4055/sad/picture/hehe?name=xiaoming&sex=2'
}
let string=url.format(obj)
console.log(string)
  • parse是将字符串转对象
  • format是将对象转字符串

第三方模块:

第三方模块可以看做是自定义模块,不过与自定义模块不同的是,第三方模块是用别人(大佬)写的,别人写完之后上传到了npm(nodejs包管理器)服务器上,让所有人可以下载。

使用第三方模块请参考npm官网(这个网站就是npm服务器上挂的网站),直接搜索你想要了解的插件,在插件的介绍的底部一般会有一个docs,这个就是帮助文档。

 nodemailer:

通过这个模块可以实现发送邮箱

先对项目进行 npm init 初始化,然后用命令 npm install nodemailer

我们用官网的示例来进行修改:

"use strict";
const nodemailer = require("nodemailer");

// async..await is not allowed in global scope, must use a wrapper
async function main() {
  // Generate test SMTP service account from ethereal.email
  // Only needed if you don't have a real mail account for testing
  let testAccount = await nodemailer.createTestAccount();

  // create reusable transporter object using the default SMTP transport
  let transporter = nodemailer.createTransport({
    host: "smtp.ethereal.email",
    port: 587,
    secure: false, // true for 465, false for other ports
    auth: {
      user: testAccount.user, // generated ethereal user
      pass: testAccount.pass // generated ethereal password
    }
  });

  // send mail with defined transport object
  let info = await transporter.sendMail({
    from: '"Fred Foo ?" <foo@example.com>', // sender address
    to: "bar@example.com, baz@example.com", // list of receivers
    subject: "Hello ✔", // Subject line
    text: "Hello world?", // plain text body
    html: "<b>Hello world?</b>" // html body
  });

  console.log("Message sent: %s", info.messageId);
  // Message sent: <b658f8ca-6296-ccf4-8306-87d57a0b4321@example.com>

  // Preview only available when sending through an Ethereal account
  console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));
  // Preview URL: https://ethereal.email/message/WaQKMgKddxQDoou...
}

main().catch(console.error);

我们修改代码需要先知道一些邮箱地址以及其对应的端口号,这些信息在哪里得到呢?当你从npm服务器上安装了nodemailer后,打开本地./node_modules/lib/well-known/services.json,大部分的邮箱服务器以及对应信息都存放在了这个json文件。

我们把代码改成了这样:

//声明严格模式
"use strict";
//引入第三方模块
const nodemailer = require("nodemailer");

//创建发送邮件的请求对象
  let transporter = nodemailer.createTransport({
    host: "smtp.qq.com",  //发送方邮箱服务器主机
    port: 465,
    secure: true, // 端口为465的话这个就为true,否则为false
    auth: {
      user: '654321@qq.com', //发送方的邮箱地址
      pass: 'tfzrbasdfdjbccc' //MTP验证码
    }
  });

//创建了一个邮件信息对象
let mailobj={
    from: '"圣诞老哥" <654321@qq.com>', //发送人和地址
    to: "123456@qq.com", // 接收方
    subject: "红玫瑰", //发送标题
    text: "梦里梦到醒不来的梦,红线里被软禁的红", //发送文本(文本信息与html只能有一个)
    //html: "<b>Hello world?</b>" //发送页面
  }
//发送邮件
transporter.sendMail(mailobj); 

最后执行transporter.sendMail(mailobj);实现发送。

注意,MTP验证码要怎么得到,登录对应邮箱的邮箱账号,

然后点击设置-》用户,往下拉,

开启POP3/SMTP服务后,就会得到MTP验证码。

同理如果要一直发短信,只要给发送短信做个计时器即可

//发送邮件
setInterval(()=>{
    transporter.sendMail(mailobj);
},1000)

扩展练习:

模拟爬虫:

我们利用https模块来模拟爬虫(http模块相同)

首先我们先来收集数据

 const http=require('https')
 const fs=require('fs')

 let url='https://world.taobao.com/'
 http.get(url,(res)=>{
    
    let rawData=''
    //主要接收到数据,就会触发data事件(数据量比较大的话会触发多次data-分段传输)
    res.on('data',(chunk)=>{
        console.log('数据传输')  
        rawData+=chunk
    }).on('end',()=>{        //监听结束事件
        console.log('数据传输完毕')
        //将请求的数据保存到本地
        fs.writeFileSync('./taobao.html',rawData)
    })
 }).on('error',()=>{    //监听错误事件
    console.log('请求错误!');
 })  

访问淘宝,并且将数据成功同步保存到了文件中

再丰富一下,对网页响应做一些判断

 const http=require('https')
 const fs=require('fs')

 let url='https://world.taobao.com/'
 http.get(url,(res)=>{
    //安全判断
    //解构复制
    const {statusCode}=res;    //请求状态码
    const contentType=res.headers['content-type'];  //文件类型
 
    console.log(statusCode,contentType)

    let error=null;
  if (statusCode !== 200) {
    error = new Error('请求失败\n' +
                      `状态码: ${statusCode}`);
  } else if (!/^text\/html/.test(contentType)) {   //正则(^text/html)验证格式类型是网页文件
    error = new Error('无效的 content-type.\n' +
                      `期望的是 application/json 但接收到的是 ${contentType}`);
  }
  if (error) {
    console.error(error.message);
    // 消费响应数据来释放缓存。
    res.resume();
    //return下面代码就不必执行了
    return;
  }


    //数据处理
    let rawData=''
    //主要接收到数据,就会触发data事件(数据量比较大的话会触发多次data-分段传输)
    res.on('data',(chunk)=>{
        console.log('数据传输')  
        rawData+=chunk
    }).on('end',()=>{        //监听结束事件
        console.log('数据传输完毕')
        //将请求的数据保存到本地
        fs.writeFileSync('./bilibili.html',rawData)
    })
 }).on('error',()=>{    //监听错误事件
    console.log('请求错误!');
 })  

上面涉及到了一些es6的特殊写法,比如解构复制

可以参考下面这两个网站

分享一些es6写法

ES6优雅写法实践

往下我们得到了网页代码数据后,接下来就是解析数据,那么我们需要安装一个插件(第三方工具)来帮助我们更快的分析想要的内容——cheerio,还是通过npm包管理工具安装就好,文档参见

再进行分析数据前我们先来简答了解一些Javascript的一个库JQuery的一些操作,例如下面这样:

const cheerio=require('cheerio')
//JQuery语法$
let $=cheerio.load('<div><p>你好</p><img src="http://www.baidu.com"></div>')
//attr:获取属性
console.log($('img').attr('src'))
console.log($('p').text())

输出:

http://www.baidu.com
你好

关于JQuery可以参考JQuery的更多,其实有点像xpath的操作

大致操作流程就是将一组html格式的字符串转换成类DOM结构,然后通过JQ语法选择其中元素

再来看一些JQ操作

const cheerio=require('cheerio')
//JQuery语法$
let $=cheerio.load('<div><p>你好</p><img src="http://www.baidu.com"></div><img src="http://www.bilibili.com"></div>')

$('img').each((index,el)=>{
    console.log($(el).attr('src'))
})

输出:

http://www.baidu.com
http://www.bilibili.com

掌握了一些JQ语法,回到我们的爬虫文件,更新一下,如下:

 const http=require('https')
 const cheerio=require('cheerio')

 let url='https://world.taobao.com/'
 
 
 http.get(url,(res)=>{
    //安全判断
    //解构复制
    const {statusCode}=res;    //请求状态码
    const contentType=res.headers['content-type'];  //文件类型


    let error=null;
  if (statusCode !== 200) {
    error = new Error('请求失败\n' +
                      `状态码: ${statusCode}`);
  } else if (!/^text\/html/.test(contentType)) {   //正则(^text/html)验证格式类型是网页文件
    error = new Error('无效的 content-type.\n' +
                      `期望的是 application/json 但接收到的是 ${contentType}`);
  } 
  if (error) {
    console.error(error.message);
    // 消费响应数据来释放缓存。
    res.resume();
    //return下面代码就不必执行了
    return;
  }


    //数据处理
    let rawData=''
    //主要接收到数据,就会触发data事件(数据量比较大的话会触发多次data-分段传输)
    res.on('data',(chunk)=>{
        console.log('数据传输')  
        rawData+=chunk
    }).on('end',()=>{        //监听结束事件
        console.log('数据传输完毕')
        //通过cheerio来进行分析
        let $=cheerio.load(rawData)  //将请求道的网页数据进行转化
        $('img').each((intdex,el)=>{
            console.log($(el).attr('src'))
        })
    })
 }).on('error',()=>{    //监听错误事件
    console.log('请求错误!');
 })  

即可以得到网页代码中src属性的内容

 

 


商业转载 请联系作者获得授权,非商业转载 请标明出处,谢谢

 

 

 

发表评论