《Python3网络爬虫开发实战》PDF及
956 2023-04-03 02:50:18
Node.js不是一门语言,是一个js运行环境。Node.js是一个基于Chrome V8引擎的JavaScript运行环境。Node.js使用了一个事件驱动、非阻塞式I/O的模型,使其轻量又高效。此外Node自带包管理工具npm(node package manager),下载前后端的包可以使用npm指令。
js:
Node.js:
通过node 文件名
来运行脚本文件,每次修改js文件需要重新执行才会生效,使用指令npm i -g nodemon
安装nodemon
,安装后通过nodemon 文件名
运行脚本文件,可以监视文件改动,自动重启。
Node.js异步编程的直接体现在回调函数上。
异步:就是一个不等待的过程。非阻塞。
优点:性能提高,可以处理大量的并发请求
fs.readFile('/etc/passwd', 'utf8', callback);
参数:
utf-8
格式,获取到的data是一个Buffer对象const fs = require('fs');//同步方法,会产生阻塞效果const data = fs.readFileSync('./runcode.js');//Buffer流console.log(data);//调用Buffer的toString方法console.log(data.toString());//会等读取文件执行完后再执行console.log('阻塞式');
异步编程,不阻塞,大大提高程序性能。
const fs = require('fs');//异步编程fs.readFile('./runcode.js', (err, data) => { //第一个参数为 err ,node中的错误优先机制 if (err) { //error.stack 属性是一个字符串,描述代码中 Error 被实例化的位置。 console.log(err.stack); return; } console.log(data.toString());})//readFile不会阻塞下列代码执行,而readFile需要时间,所以下列代码会先执行console.log('非阻塞式');
setTimeout(()=>{},time)
就是典型的非阻塞。阻塞是按顺序执行的,而非阻塞是不需要按顺序执行的。
const fs = require('fs');// 使用promiseconst { promisify} = require('util');// promisify 将fs.readFile包装成promise对象const readFile = promisify(fs.readFile);async function asyncReadFile() { try { //让异步代码同步化 const data = await readFile('./runcode.js'); console.log(data.toString()); } catch (error) { //打印错误的位置 console.log(error.stack); }}asyncReadFile();
const fs = require('fs');const { promisify} = require('util');const readFile = promisify(fs.readFile);function* read() { yield readFile('./runcode.js');}//获取Generator对象let gen = read();gen.next().value.then((res) => { console.log(res.toString());}).catch((err) => { console.log(err);})
// 创建一个长度为 10 的 Buffer对象const buf1 = Buffer.alloc(10);console.log(buf1);// 创建一个长度为 10、且用 0x1 填充的 Buffer。 const buf2 = Buffer.alloc(10, 1);console.log(buf2);// 通过数据创建,创建一个包含UTF-8 编码字节const buf3 = Buffer.from('hello world');console.log(buf3);// 创建一个包含字节 [1, 2, 3] 的 Buffer。const buf4 = Buffer.from([1, 2, 3]);console.log(buf4);//写入buf1.write('hello');console.log(buf1);//当填充满后不再填充buf1.write('hello buffer');//读取console.log(buf1.toString()); //hello buff//转换编码格式,默认 utf-8console.log(buf1.toString('base64')); //aGVsbG8gYnVmZg==//合并const buf5 = Buffer.concat([buf1, buf3]);console.log(buf5.toString());//hello buffhello world
此外还有Buffer.compare(buf1, buf2)
主要用于 Buffer 实例数组的排序等函数。
管道提供了一个输出流到输入流的机制。通常我们用于从一个流中获取数据并将数据传递到另外一个流中。
复制文件
const fs = require('fs');//创建可读流const readerStream = fs.createReadStream('./readme.md');//创建可写的流const writerStream = fs.createWriteStream('./test.txt');//通过管道进行传输readerStream.pipe(writerStream);console.log('复制完毕');
链式是通过连接输出流到另外一个流并创建多个流操作链的机制。链式流一般用于管道操作
压缩文件
const fs = require('fs');const zlib = require('zlib');const gzip = zlib.createGzip();fs.createReadStream('./test.txt').pipe(gzip).pipe(fs.createWriteStream('./test.zip'));console.log('文件压缩成功');
解压文件
const fs = require('fs');const zlib = require('zlib');const gunzip = zlib.createGunzip();fs.createReadStream('./test.zip').pipe(gunzip).pipe(fs.createWriteStream('./1.txt'));console.log('文件解压成功');
事件循环
事件驱动程序
整个事件驱动的流程就是这么实现的,非常简洁。有点类似于观察者模式,事件相当于一个主题(Subject),而所有注册到这个事件上的处理函数相当于观察者(Observer)。
Node.js 有多个内置的事件,我们可以通过引入 events 模块,并通过实例化 EventEmitter 类来绑定和监听事件。
// 引入 events 模块const events = require('events');// 创建 eventEmitter 对象const eventEmitter = new events.EventEmitter();// 绑定事件处理程序 定好一个主题eventEmitter.on('conn', () => { console.log('连接成功'); //触发另外的事件处理 eventEmitter.emit('data_receive');});// 绑定事件eventEmitter.on('data_receive', () => { console.log('数据接收成功');})// 观察者 观察对应的主题要做什么事情eventEmitter.emit('conn');console.log('程序执行完毕');
为了让Node.js的文件可以相互调用,Node.js提供了一个简单的模块系统。模块是Node.js 应用程序的基本组成部分,文件和模块是一一对应的。换言之,一个 Node.js 文件就是一个模块,这个文件可能是JavaScript 代码、JSON 或者编译过的C/C++ 扩展。
Node.js提供了exports和require两个对象,其中exports是模块公开的接口,require用于从外部获取一个模块的接口。
创建模块
exports.name = () => { console.log('Holo');}//也可抛出多个exports.age = () => { console.log(18);}//还可抛出数组、变量、对象等
引入模块
let Obj = require('./hello');Obj.name()//Obj.age();
抛出构造函数
function Dog() { let name; this.setName = function (myName) { name = myName; } this.getName = function () { console.log('hello' + name); }}module.exports = Dog;
引入
const Dog = require('./module');const d1 = new Dog();d1.setName('小黄');d1.getName();
如果通过module.exports
抛出对象,抛出的就是当前的对象,如果是通过exports
抛出,会是一个键值对的形式挂载到对象上{ name: [Function], age: [Function], dog: '小黄' }
。并且exports
在一个文件中可以有多个抛出,而module.exports
只能有一个抛出。
Node.js 的 require方法中的文件查找策略如下:
由于Node.js中存在4类模块(原生模块和3种文件模块)
尽管require方法极其简单,但是内部的加载却是十分复杂的,其加载优先级也各自不同。如下图所示:
nodejs.jakeyu.top/#%E6%96%87%…
nodejs.jakeyu.top/#os-%E6%A8%…
nodejs.cn/api/url.htm…
注意:使用WHATWG
标准的新API可以直接const myURL = new URL('https://user:pass@sub.host.com:8080/p/a/t/h?query=string#hash');
,不需要再去导入const url = require('url');
。
nodejs.jakeyu.top/#path-%E6%A…
path.join()
方法会将所有给定的 path 片段连接到一起(使用平台特定的分隔符作为定界符),然后规范化生成的路径。__dirname
: 表示当前执行脚本所在的目录。
path.resolve()
方法会将路径或路径片段的序列解析为绝对路径。const path = require('path');//二者都能获取绝对路径名console.log(path.join(__dirname, 'demo1.js'));console.log(path.resolve('demo1.js'));
path.extname()
方法会返回 path 的扩展名注意:如果在服务器端使用path.resolve()
方法返回的是服务器上的一个绝对路径,使用path.join()
方法返回的是当前电脑上的绝对路径。建议使用path.join()
,以免出错。
搭建服务器
//引入http模块const http = require('http');//创建Server对象const app = http.createServer((req, res) => { //中文会出现乱码,需要进行设置 res.end('hello node.js');})//监听端口号app.listen(3000);
//引入http模块const http = require('http');//引入fs模块const fs = require('fs');//创建Server对象const app = http.createServer((req, res) => { /* url: '/about', method: 'GET', */ const { url, method } = req; //对路由进行判断 if (url === '/index' && method === 'GET') { //返回一个首页给浏览器 fs.readFile('./static/index.html', 'utf-8', (err, data) => { if (err) { //设置状态码 res.statusCode = 500; //返回错误信息 res.end('500 - Interval Serval Error!'); } //成功 res.statusCode = 200; //设置响应头 表明返回回去的一定是一个html //一般情况下不会特意去指定,如果需要指定,一定要根据文件类型去指定 //mime 文件类型 https://www.w3school.com.cn/media/media_mimeref.asp res.setHeader('Content-Type', 'text/html'); //返回信息 res.end(data); }); } else if (url === '/about' && method === 'GET') { fs.readFile('./static/about.html', 'utf-8', (err, data) => { if (err) { res.statusCode = 500; res.end('500 - Interval Serval Error!'); } res.statusCode = 200; res.setHeader('Content-Type', 'text/html'); res.end(data); }) } else if (req.headers.accept.indexOf('image/*') !== -1 && method === 'GET') { //对图片进行处理 注意:这边就是 `image`,匹配的是一个mime类型,而不是你的文件夹名 console.log(url); //流的方式 fs.createReadStream(__dirname + url).pipe(res); } else if (url === '/user' && method === 'GET') { //处理json数据 res.statusCode = 200; res.setHeader('Content-Type', 'application/json'); res.end(JSON.stringify([{ name: 'Alex' }])) } else { //中文会出现乱码,需要进行设置 res.end('hello node.js'); }})//监听端口号app.listen(3000);
npm init
初始化package name: (node)--- 包名version: (1.0.0) 1.0.1--- 版本description:--- 描述entry point: (Buffer.js) index.js--- 入口文件test command:--- 测试git repository:--- git地址keywords: Alex--- 关键字author: Alex--- 作者license: (ISC)--- 认证
也可以直接npm init --yes
直接创建,然后再去修改配置文件。
npm install express --save
为了能够安装更快,也可使用淘宝镜像安装 cnpm i express -s
HelloWorld
//引入expressconst express = require('express')//引入fsconst fs = require('fs');//引入pathconst path = require('path');//创建app实例const app = express()const port = 3000//匹配的路由地址app.get('/', (req, res) => res.send('Hello World!'))//index路由app.get('/index', (req, res) => { fs.readFile('./static/index.html', 'utf-8', (err, data) => { if (err) { //设置状态码 res.statusCode = 500; //返回错误信息 res.end('500 - Interval Serval Error!'); } //成功 res.statusCode = 200; //设置响应头 表明返回回去的一定是一个html res.setHeader('Content-Type', 'text/html'); //返回信息 res.end(data); });})//匹配所有路由app.get('*', (req, res) => { res.setHeader('Content-Type', 'image/*'); // console.log(path.resolve(req.url)); // D:\static\images\timg.webp // console.log(path.join(__dirname, req.url)); // D:\code\MicrosoftVSCodeProjects\Study\node\static\images\timg.webp fs.readFile(path.join(__dirname, req.url), (err, data) => { if (err) { throw err; } //end()或send() res.send(data); })})//监听端口app.listen(port, () => console.log(`Example app listening on port ${port}!`))
MExpress.js
const Application = require('./application')function MExpress() { return new Application();}module.exports = MExpress;
application.js
// 需求// 1.实现http服务器// 2.实现get路由请求const http = require('http');const url = require('url');class Application { constructor() { this.router = []; } get(path, cb) { this.router.push({ path: path, method: "GET", handle: cb }) } listen() { // 创建http服务器 http.createServer((req, res) => { // 获取前端给我的url路径 pathname const { pathname } = url.parse(req.url); for(const route of this.router){ if(route.path === pathname){ route.handle(req,res); return; } // 处理其他的路由 if(route.path === '*'){ route.handle(req,res); return; } } }).listen(...arguments) }}module.exports = Application;