前言:
承接前面的内容我们来继续了解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的特殊写法,比如解构复制
可以参考下面这两个网站
往下我们得到了网页代码数据后,接下来就是解析数据,那么我们需要安装一个插件(第三方工具)来帮助我们更快的分析想要的内容——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属性的内容
欢迎访问我的博客:is-hash.com
商业转载 请联系作者获得授权,非商业转载 请标明出处,谢谢