MongoDB

非关系型数据库

模式

schemas用于描述数据表

模型

modelsschemas发布生成的模型,有增删改查的行为方法

实例

collect帮助表进行读写操作

创建

  1. //安装mongoose
  2. npm i -S mongoose@5.4.21
  1. //基于koa服务端框架编写:
  2. //1.创建并进入目录src > dbs
  3. //2.创建配置文件 config.js
  4. //3.配置数据库
  5. module.exports = {
  6. //协议:端口/数据库名称
  7. dbtest: 'mongodb://127.0.0.1:27017/dbtest'
  8. }
  9. //4.创建dbs > models目录
  10. //5.创建文件person.js
  11. //6.引入mongoose
  12. const mongoose = require('mongoose');
  13. //7.创建schema模式
  14. let personSchema = new mongoose.Schema({
  15. name: String,
  16. age: Number
  17. });
  18. //8.定义并导出模型
  19. module.exports = mongoose.model('Person', personSchema);
  20. //9.连接数据库 src > app.js
  21. const mongoose = require('mongoose');
  22. const dbConfig = require('./dbs/config');
  23. mongoose.connect(dbConfig.dbtest, {
  24. useNewUrlParser: true
  25. });

操作

对数据库进行增删改查操作

  1. //编写增加接口
  2. //1.路由文件routes > users.js 引入模型
  3. const Person = require('../dbs/models/person');
  4. //2.新增路由路径 并实例化模型 将数据保存到数据库里
  5. //注意:操作数据库都是异步操作
  6. router.post('/addPerson', async function (ctx, next) {
  7. const person = new Person({
  8. name: ctx.request.body.name,
  9. age: ctx.request.body.age
  10. });
  11. await person.save();
  12. //返回终端显示 code = 0
  13. ctx.body = {
  14. code: 0
  15. }
  16. });
  17. //3.postman尝试发送post请求 "name=xiaowang&age=18"
  18. //服务器成功返回{"code": 0}
  19. //4.打开compass查看dbtest数据库person模型里成功存储post提交的数据信息
  1. //编写查询接口
  2. //1.新增路由路径 通过模型查询
  3. router.post('/getPerson', async function (ctx, next) {
  4. const res = await Person.findOne({
  5. name: ctx.request.body.name,
  6. });
  7. //返回终端显示 code = 0 和 查询结果
  8. ctx.body = {
  9. code: 0,
  10. res
  11. }
  12. });
  13. //2.postman尝试发送post请求 "name=xiaowang"
  14. //服务器成功返回{"code": 0} 和 查询到的结果
  1. //编写更改接口
  2. //1.新增路由路径 通过模型更改
  3. router.post('/updatePerson', async function (ctx, next) {
  4. const res = await Person.where({
  5. name: ctx.request.body.name,
  6. }).update({
  7. age: ctx.request.body.age
  8. });
  9. //返回终端显示 code = 0
  10. ctx.body = {
  11. code: 0
  12. }
  13. });
  14. //2.postman尝试发送post请求 "name=xiaowang&age=20"
  15. //服务器成功返回{"code": 0}
  16. //3.打开compass刷新person模型显示更新后的数据
  1. //编写删除接口
  2. //1.新增路由路径 通过模型更改
  3. router.post('/removePerson', async function (ctx, next) {
  4. const res = await Person.where({
  5. name: ctx.request.body.name,
  6. }).remove();
  7. //返回终端显示 code = 0
  8. ctx.body = {
  9. code: 0
  10. }
  11. });
  12. //2.postman尝试发送post请求 "name=xiaowang"
  13. //服务器成功返回{"code": 0}
  14. //3.打开compass刷新person模型显示删除后的数据

NuxtJS

概念

前后端分离概念:

  • 前端:

    • 写页面和业务脚本
  • 中间层(后端node):

    • 拿到数据
    • 登录/注册
    • redis存储
    • 验证
    • 组件html
    • 返回完整的html静态页面
    • 向后端请求数据
  • 后端:

    • 写数据接口
    • 数据库对接
    • 数据返回

问题:Nuxt做了什么?

  • vue组件集合
  • Nuxt页面打包
  • Nuxt请求数据
  • 组件与数据结合
  • 组件html

官方文档:https://zh.nuxtjs.org/

基于vuejs通用应用框架

关注于UI应用渲染,对客户端服务端基础架构的组织实现的,还预设了vuejs开发渲染应用所需要的各种配置

安装

SSR + Nuxtjs

  1. //创建Nuxtjs项目脚手架
  2. npx create-nuxt-app@2 my-first-nuxt-app

什么是服务端渲染?

路由

Nuxt的路由机制是一个.vue组件文件就一个子路由,主要根据pages目录的文件嵌套关系来确定路由的嵌套关系

pages目录直接定义组件,不用配置路由文件即可创建路由路径/about

  1. //nuxt脚手架根目录下pages目录下新建about.vue
  2. <template>
  3. <div>这是关于页面</div>
  4. </template>

布局

布局模板layouts

  1. //根目录下layouts目录下的模板可以被其他组件指定并继承该模板的布局和样式
  2. //如pages > aaa.vue
  3. <template>...</template>
  4. <script>
  5. export default{
  6. //这里可以指定layouts目录下的模板名称
  7. layout: 'bbb'
  8. }
  9. </script>

标签

<nuxt />

该标签占位在根组件,实际是子组件的文本内容

<nuxt-link>

该标签是跳转元素标签,相当于a标签

  1. <nuxt-link to="/changeCity"></nuxt-link>

接口

编写后台接口

  1. //server目录新建dbs数据库目录
  2. //dbs数据库目录里创建models模型目录
  3. //server > dbs > models模型目录创建users.js文件
  4. //server > dbs目录下创建config.js配置文件(数据库相关信息)
  5. //server目录新建interface接口目录
  6. //interface目录新建utils工具目录
  7. //server > interface新建users.js文件
  8. //server > interface > utils新建axios.js文件(封装全局使用axios)
  9. //server > interface > utils新建passport.js文件(验证相关权限)

案例

案例:JS++官网移动版

这是一个基于服务端渲染,数据来源于爬虫制作课堂官网的移动版

技术:

  • NuxtJS
  • vuex(内置)

功能:

  • 首页
  • 列表页

    • tab栏点击会切换页面
    • tab栏点击会与屏幕左侧贴齐
  • 错误页
  • 移动端和网页端适配时切换

案例图片:

MongoDB&Redis&NuxtJS&Puppeteer - 图1

MongoDB&Redis&NuxtJS&Puppeteer - 图2

启动:

  1. npm run dev

接口:

  • 请求首页数据:/api/get_home_data
  • 请求列表页数据:/api/get_list_data
  • 请求列表页课堂数据:/api/get_course_data

源码目录:

  1. ├─.editorconfig
  2. ├─.gitignore
  3. ├─nuxt.config.js - nuxt服务器配置文件/插件/样式加载/头部信息
  4. ├─app.html - nuxt提供的模板/移动端网页端适配/乱码BUG修复
  5. ├─package-lock.json
  6. ├─package.json
  7. ├─README.md
  8. ├─utils
  9. | ├─http.js - 封装axios请求
  10. | tools.js - 工具方法/切换tab定位/课堂数据过滤
  11. ├─store
  12. | ├─index.js - store仓库/容器/方法
  13. ├─static - 不被打包的静态目录
  14. | ├─favicon.ico
  15. ├─server - 后端服务器
  16. | ├─index.js
  17. | ├─services
  18. | | ├─Collection.js
  19. | | ├─Course.js
  20. | | ├─CourseTab.js
  21. | | ├─RecomCourse.js
  22. | | ├─Slider.js
  23. | | ├─Student.js
  24. | | Teacher.js
  25. | ├─routes
  26. | | index.js
  27. | ├─libs
  28. | | utils.js
  29. | ├─db
  30. | | ├─db_connect.js
  31. | | ├─models
  32. | | | ├─aboutus.js
  33. | | | ├─agencyInfo.js
  34. | | | ├─collection.js
  35. | | | ├─course.js
  36. | | | ├─courseTab.js
  37. | | | ├─recomCourse.js
  38. | | | ├─slider.js
  39. | | | ├─student.js
  40. | | | teacher.js
  41. | ├─controllers
  42. | | Home.js
  43. | ├─configs
  44. | | ├─db.js
  45. | | ├─db_type.js
  46. | | ├─env.js
  47. | | ├─link.js
  48. | | ├─manual.js
  49. | | ├─nav.js
  50. | | ├─page.js
  51. | | ├─qiniu.js
  52. | | ├─qr.js
  53. | | url.js
  54. ├─plugins - 存放前端使用的插件文件(生产依赖文件)
  55. | ├─vue-awesome-swiper.js
  56. | vue-lazyload.js
  57. ├─pages - 视图绑定/前后端数据请求/下拉功能实现
  58. | ├─index.vue - 首页
  59. | ├─list.vue - 列表页
  60. ├─middleware
  61. ├─layouts
  62. | ├─default.vue
  63. | README.md
  64. ├─config
  65. | config.js
  66. ├─components
  67. | ├─list
  68. | | ├─listTab
  69. | | | ├─index.vue
  70. | | | tabItem.vue
  71. | ├─index
  72. | | ├─teacher
  73. | | | ├─index.vue
  74. | | | teacherItem.vue
  75. | | ├─swiper
  76. | | | ├─index.vue
  77. | | | swiperItem.vue
  78. | | ├─recomCourse
  79. | | | ├─courseItem.vue
  80. | | | index.vue
  81. | | ├─courseNav
  82. | | | ├─index.vue
  83. | | | navItem.vue
  84. | | ├─cooperation
  85. | | | ├─cooperationItem.vue
  86. | | | index.vue
  87. | | ├─collection
  88. | | | ├─collectionItem.vue
  89. | | | index.vue
  90. | ├─common
  91. | | ├─scrollWrapper
  92. | | | index.vue
  93. | | ├─pullingDownLoading
  94. | | | index.vue
  95. | | ├─mainTitle
  96. | | | index.vue
  97. | | ├─header
  98. | | | ├─BackIcon.vue
  99. | | | ├─index.vue
  100. | | | ├─ListIcon.vue
  101. | | | Logo.vue
  102. | | ├─footer
  103. | | | index.vue
  104. | | ├─error
  105. | | | index.vue
  106. | | ├─course
  107. | | | ├─courseItem.vue
  108. | | | index.vue
  109. ├─assets - 被打包的资源文件目录
  110. | ├─styles
  111. | ├─scripts
  112. | ├─images

源码地址: https://gitee.com/kevinleeeee/crawler-txcourse-mobile-nuxt-demo

Redis

NoSql非关系型数据库(not-only sql

概念

Redis——C语言开发——键值存储数据库——处理大量数据的高访问负载

  • 优势:快速查询

  • 劣势:存储的数据缺少结构化

Redis的庞大用户群体:新浪微博、知乎网、GitHubStack,Overflow等。

区别:

  • Redis:内存数据库

    • 访问快/内存压力大/缓存公共数据和登录信息
  • MySQL:硬盘数据库

    • 访问较慢/内存压力小/静态数据集合/非公共数据/网站的视图数据

应用场景1:

  • high performance:对数据库高并发读写
  • huge storage:对海量数据的高效率存储和访问
  • high scalability && high availability:对数据库的高可扩展性和高可用性

应用场景2:

缓存(数据查询、新闻内容、商品内容)、分布式集群架构中的session分离、任务队列、数据过期处理等。

无状态

用户状态存储管理,记录用户访问的记录

HTTP是无状态的,利用服务器session存储信息

安装

  1. //全局安装redis
  2. //github下载地址:
  3. //https://github.com/microsoftarchive/redis/releases/tag/win-3.2.100
  4. //安装后cmd找到目录打开redis
  5. C:\Program Files\Redis>redis-server redis.windows.con
  6. //项目安装依赖
  7. npm i -S redis@3.0.2

启动

  1. //暂停redis
  2. redis-server --service-stop
  3. //启动redis
  4. redis-server --service-start
  5. //or
  6. .\redis-server
  7. //另一个终端启动客户端
  8. .\redis-cli

使用

  1. //操作redis
  2. //设置
  3. set name 'xxx'
  4. //获取
  5. get name
  6. //获取redis所有key
  7. keys *
  8. //删除key
  9. del name
  10. //退出客户端
  11. exit

koa2配置redis

  1. //安装koa-redis和koa-generic-session
  2. npm i -S koa-redis@4.0.1
  3. npm i -S koa-generic-session@2.0.4
  1. //基于koa服务端框架编写:
  2. //app.js引入
  3. const Redis = require('koa-redis');
  4. const session = require('koa-generic-session');
  5. //对session进行加密
  6. app.keys = ['some secret hurr'];
  7. //使用中间件 连接redis
  8. app.use(session({
  9. store: new Redis()
  10. }))
  1. //编写测试的中间件
  2. //src > middleware > koa-mid.js
  3. function mid(ctx) {
  4. //打印页面路径
  5. console.log('midtest', ctx.path);
  6. ctx.session.count++;
  7. }
  8. module.exports = function () {
  9. return async function (ctx, next) {
  10. mid(ctx);
  11. await next();
  12. }
  13. }
  14. //回到浏览器访问http://localhost:3000/
  15. //在Application里cookies存储新的sid字段保存key/value
  16. //koa.sid.sig:p5lZOKL2rOIEEkLjl8QEnVabvBU
  17. //koa.sid:u15MkW5tT2KfIXCOZ_jofaqJVde6KtWT
  18. //说明用户下次访问时一直拿到该session的值来区分哪个用户进行访问
  1. //自定义session键名称
  2. app.use(session({
  3. key: 'test',
  4. prefix: 'testprefix'
  5. store: new Redis()
  6. }))
  7. //回到浏览器访问http://localhost:3000/
  8. //在Application里cookies存储新的sid字段保存test名字的key

关于session存储到redis

  • session数据量小
  • session不考虑数据丢失问题
  • session访问度高,要求访问快,性能高

问题:什么情况不适合redis?

  • 操作频率不高的数据
  • 数据无法承受丢失的结果
  • 数据量大,内存无法承受

项目中配置redis

  1. //1.安装依赖
  2. npm i -S koa-redis@4.0.1
  3. npm i -S koa-generic-session@2.0.4(操作sessionredis用)
  4. //2.引入
  5. const redis = require('redis');
  6. //3.创建redis客户端
  7. const red = redis.createClient(['6379', '127.0.0.1']);
  8. //4.监听错误
  9. red.on('error', (error) => {
  10. console.error('Redis error: ' + error);
  11. });
  12. //5.设置键名和超时
  13. function redisSet(key, value, timeout = 60 * 60) {
  14. if (typeof (value) === 'object') {
  15. value = JSON.stringify(value);
  16. }
  17. red.set(key, value);
  18. red.expire(key, timeout);
  19. }
  20. //6.获取键名的值
  21. function redisGet(key) {
  22. return new Promise((resolve, reject) => {
  23. red.get(key, (error, value) => {
  24. //错误时
  25. if (error) {
  26. reject(error);
  27. return;
  28. }
  29. //值为空时
  30. if (value == null) {
  31. resolve(null);
  32. return;
  33. }
  34. //JSON字符串时
  35. //尝试,忽略错误
  36. try {
  37. resolve(JSON.parse(value));
  38. } catch (e) {
  39. resolve(value);
  40. }
  41. })
  42. });
  43. }

Puppeteer

nodejs提供的一个库,实现爬虫页面程序,它提供一个高级API来通过DevTools协议来控制chrome

它还能做:

  • 生成页面的屏幕截图和 PDF
  • 抓取 SPA(单页应用程序)并生成预渲染内容(即“SSR”(服务器端渲染))
  • 自动化表单提交、UI 测试、键盘输入等
  • 创建最新的自动化测试环境。使用最新的 JavaScript 和浏览器功能直接在最新版本的 Chrome 中运行测试
  • 捕获您网站的时间线轨迹以帮助诊断性能问题
  • 测试 Chrome 扩展程序

搭建

koa2环境

  1. //1.创建项目:koa2 + 项目名称
  2. koa2 crawler-puppeteer-txcourse-demo
  3. //2.安装依赖
  4. npm install
  5. //3.安装爬虫库 Puppeteer
  6. npm i -S puppeteer@2.1.1

编写

编写爬虫程序

  1. //4.在routes目录下的index.js里
  2. //4.1 引入爬虫依赖
  3. const pt = require('puppeteer');
  4. //4.2 在请求响应路由程序里编写爬虫程序
  5. router.get('/', async (ctx, next) => {
  6. //爬虫程序编写区域
  7. ...
  8. });
  9. //4.3 发起启动爬虫程序
  10. const broswer = await pt.launch();
  11. //4.4 配置爬取页面
  12. const url = 'https://msiwei.ke.qq.com/',
  13. //4.5 在浏览器里启动新的标签页
  14. const pg = await broswer.newPage();
  15. //4.6 等待新页面打开url地址
  16. //第二参数为配置项
  17. await pg.goto(url, {
  18. //超时
  19. timeout: 30 * 1000,
  20. //直到完成 networkidle2官方推荐(一定时间内没有发送请求证明爬取完成)
  21. waitUntil: 'networkidle2'
  22. });
  23. //4.7 分析页面后返回结果
  24. const result = await pg.evaluate(() => {
  25. //定义数据的容器(接收爬取后的数据)
  26. let data = [];
  27. //分析爬取内容
  28. ...
  29. //把内容存到容器里
  30. //返回爬取的容器
  31. return data;
  32. }
  33. //5.爬取数据后关闭浏览器
  34. await broswer.close();

查看

查看爬取结果

  1. //1.启动项目
  2. npm run dev
  3. //2.访问localhost:3000
  4. //3.等待爬取
  5. //4.爬取完毕,终端打印爬取后的数组数据
  6. [{...},{...},{...}]

子进程

开启子进程开启爬虫程序,建立单独的文件管理子进程pupeteer目录下的crawler.js自己执行的脚本,存放爬虫程序

  1. //1.拆分请求路由下爬虫程序到子进程文件中
  2. //2.路由文件引入子进程库
  3. const cp = require('child_process');
  4. //3.读取子进程脚本文件
  5. router.get('/', async (ctx, next) => {
  6. const script = resolve(__dirname, '../puppeteer/crawler.js')
  7. //4.启动子进程
  8. const child = cp.fork(script, []);
  9. //5.完善成功/退出/失败时程序日志
  10. child.on('message', (data) => {...});
  11. child.on('exit', (code) => {...});
  12. child.on('error', (err) => {...});
  13. });

案例

案例:爬虫系统

实现一个专门爬虫程序脚本的系统,如爬取腾讯课堂官网,一个课程管理后台的API后端

功能:

  • 主进程管理
  • 子进程管理
  • 多个不同目标网页的爬虫程序抽离
  • 将爬虫后的图片上传至七牛服务器
  • 数据库MySQL上传
  • 访问服务器需要携带cookie(实现登录无状态访问)
  • 账号管理数据库

技术:

  • koa2
  • puppeteer:爬虫库
  • nanoid:随机生成id
  • qiniu:七牛库
  • sequelize:可以操作许多数据库的程序(如MySQL)

    • 可以建表(authenticate()/define()/sync())
    • 增删改查
    • 避免取手动直接操作数据库
    • 避免使用SQL语句
    • 对象的方式模拟操作数据表
    • 需要依赖mysql2
    • 数据入表
  • redis :保存用户数据信息
  • session:保存用户数据信息
  • crypto:密码明文加密
  • koa2-cors:解决客服端请求跨域

项目启动:

  1. 启动后端:

    1. npm run dev
    2. 开启服务phpStudy里的MySQLApache
    3. 访问数据库网页(删除所有表)
    4. 同步所有数据表(重置新增表)
    5. 访问七牛空间(清空图片存储)
  2. 启动前端后台项目(重新爬取数据)

    1. npm start
  3. 启动前端前台项目

爬取接口:

API接口:

redis终端操作:

  • 找到redis目录:C:\Program Files\Redis
  • 终端1:开启服务.\redis-server
  • 终端2:进入服务器.\redis-cli

    • 查询keys *
    • 获取get 'xxx'
    • 设置set name 'xxx'

数据库创建步骤:

  1. 定义入口文件导入数据库配置信息
  2. 创建一个数据库(new Sequelize(数据库名称, MySQL用户名密码, 配置项))
  3. 定义各种表模型(new Sequelize().define(表名称, 配置字段对象))
  4. 执行同步(new Sequelize().sync())将表导入数据库
  5. 定义数据项
  6. 对数据项进行增删改查(new TeacherService())
  7. 数据入库(addTeacher(data))

数据库管理:

数据库命令操作:

  • 执行同步程序来建表:node db/sync.js

图床服务器管理:

项目目录:

  1. ├─app.js - 服务器/路由中间件/使用session
  2. ├─package.json
  3. ├─db - 数据库目录
  4. | ├─sync.js - 同步程序运行模型表的文件
  5. | ├─models - 模型表
  6. | | ├─aboutus.js - 描述aboutus的表
  7. | | ├─teacher.js - 描述teacher的表
  8. | | ├─student.js - 描述student的表
  9. | | ├─Course.js - 描述course的表
  10. | | ├─CourseTab.js - 描述course_tab的表
  11. | | ├─collection.js - 描述collection的表
  12. | | ├─recomCourse.js - 描述recom_course的表
  13. | | ├─agencyInfo.js - 描述agency_info的表
  14. | | ├─index.js - 出口文件
  15. | | slider.js - 描述slider的表
  16. | ├─connections - 创建数据库的入口文件
  17. | | ├─redis_connect.js - 创建redis客户端程序
  18. | | mysql_connect.js - 实例化创建数据程序
  19. ├─routes
  20. | ├─admin.js - 理由请求/admin/create_admin 执行控制器
  21. | ├─crawler.js - 路由请求路径/crawler 执行控制器
  22. | index.js - 路由请求路径/ 执行控制器
  23. ├─middlewares - 中间件
  24. | loginCheck.js - 处理是否登录/判断是否带有cookie/session信息
  25. ├─libs
  26. | ├─crawler.js - 封装一个爬虫主进程程序
  27. | ├─redisClient.js - 封装redis里的set/get方法
  28. | utils.js - 子进程工具/管理进程状态日志/爬虫工具/上传工具/加密
  29. ├─crawlers - 爬取DOMjQuery逻辑代码(爬虫文件)
  30. | ├─aboutus.js - 关于页数据
  31. | ├─teacher.js - 首页老师列表
  32. | ├─student.js - 首页学生列表
  33. | ├─course.js - 课堂页课堂列表
  34. | ├─courseTab.js - 课堂页课堂tab列表
  35. | ├─collection.js - 首页列表数据(合辑推荐)
  36. | ├─recomCourse.js - 首页推荐列表
  37. | ├─agencyInfo.js - 首页标题栏
  38. | slider.js - 首页轮播图
  39. ├─controllers - 专门控制器文件处理爬虫程序
  40. | ├─Admin.js - 实例化访问管理路径新建管理员账户/密码加密
  41. | ├─Index.js - 实例化访问根路径服务器响应相应内容
  42. | ├─Crawler - 实例化爬虫数据的方法集合类
  43. | | ├─aboutus.js
  44. | | ├─agencyInfo.js
  45. | | ├─collection.js
  46. | | ├─course.js
  47. | | ├─courseTab.js
  48. | | ├─index.js - 出口文件/新增上传七牛方法/数据入数据库方法
  49. | | ├─recomCourse.js
  50. | | ├─sliderData.js
  51. | | ├─student.js
  52. | | teacher.js
  53. ├─services - 服务目录/每一个表对应着每一个服务/实例化一个新的服务
  54. | ├─Aboutus.js - 对数据库里的aboutus表进行更改
  55. | ├─Teacher.js - 对数据库里的teacher表进行更改
  56. | ├─Student.js - 对数据库里的student表进行更改
  57. | ├─Course.js - 对数据库里的course表进行更改
  58. | ├─CourseTab.js - 对数据库里的courseTab表进行更改
  59. | ├─Collection.js - 对数据库里的collection表进行更改
  60. | ├─RecomCourse.js - 对数据库里的recomCourse表进行更改
  61. | ├─AgencyInfo.js - 对数据库里的agencyInfo表进行更改
  62. | Slider.js - 对数据库里的slider表进行更改
  63. ├─config
  64. | ├─config.js - 七牛账号/爬虫页面/session&cookie&redis信息配置/管理员账户/密钥
  65. | ├─db_config.js - 数据库/redis配置文件
  66. | ├─db_type_config.js - 定义数据库类型的配置文件
  67. | ├─env_config.js - 定义环境变量的配置文件
  68. | error_config.js - 定义成功或错误的状态码信息配置文件
  69. ├─views - 视图模板
  70. | index.ejs - 根路径视图html
  71. ├─bin - koa2服务器主程序
  72. | www

源码地址(非开源):