小程序云开发快速入门(1/4)

前言

从上次完成了码仔备忘录本地版本后,码仔就养成了每天记录备忘录的好习惯,每周早上会记录下自己要做的任务,然后晚上在复盘一下今天的计划是否完成。

image.png
有一天,码仔看到它最喜欢的码妞在一旁愁眉苦脸。

image.png
码仔:“怎么了?”
码妞:“工作事物太多了,总是忘记工作上的一些事情”

码仔心里暗喜,这不是和我之前一样吗?让她用用我的码仔备忘录,她一定会觉得我很厉害,hahahaha。

image.png
码仔:“我教你一个方法”
码妞:“什么方法?”
码仔:“用我的码仔备忘录”

于是码妞用上了码仔备忘录进行工作日志记录,突然有一天码妞非常生气的跑到码仔身边。

image.png
码妞大声骂道:“死猴子,我就知道你写的东西不靠谱,我今天换了个手机,然后再次打卡你的备忘录小程序,结果数据都没有了!”
码仔解释道:“目前只支持单机版,换手机小程序本地缓存就没了,所以的记录就没有了。”

码仔为了解决码妞数据问题,当天码仔熬夜查资料。

image.png
终于找到了小程序云开发!码仔打算将把备忘录的本地数据存储在云端。

在使用云开发之前,让我们先来了解一下云开发的一些基本信息,以便我们后续更好的学习云开发。

image.png

什么是云开发?

云开发是可以帮助我们快速成为全栈的一种后端云服务,采用的是Serverless的架构。开发者无须搭建服务器,可直接使用其中的云数据库、云存储、云函数等云服务基础功能。

那么这个时候你可能会想,这和现在的传统开发模式有什么区别呢?下面通过现实生活中盖房子的过程来了解传统开发模式与云开发模式的区别。

如果传统方式来盖房子需要6步:
1)将房子的地基打好,设计整理结构。(后端云服务基础架构)
2)打地梁,地梁也是决定房子是否稳固的关键。(搭建云数据库)
3)主体的砌筑,将房子的基本结构盖好。(搭建云存储)
4)在步屋内填上土,砸夯,将地面砸实。(搭建云函数)
5)在屋顶铺上水泥,封实。(提供静态托管和扩展能力)
6)装修成自己喜欢的风格。(编写业务需求逻辑代码)

而云开发模式只有一步,即装修成自己喜欢的风格。可以看到图1-1展示的是传统开发需要管理的基础资源与云开发需要管理的基础资源的对比,可以帮助我们更清晰的了解两者之间的差距。

image.png
图1-1 传统开发需要管理的基础资源VS云开发需要管理的基础资源

就这一步即可。云开发提供完整的后端云服务,提供数据库、存储、函数、静态托管等基础能力,以及扩展能力,无须管理基础架构。相比较传统的开发模式,云开发至少可节省50%的人力成本、交付效率提升70%。

实战云开发改造

码仔为了获取码妞肯定,码仔下定决心,决定通宵也要搞定小程序云开发!

image.png

云开发模式调整

在此之前我们需要把原来码仔备忘录项目改成云开发项目,所以需要先把项目从项目管理中先删除。(如果是直接新建的云开发项目可以忽略这一步)

首先,先进入小程序项目管理页面:

image.png
然后点击右上角「管理」按钮进入该页面的管理状态。

image.png
然后选中你之前的单机版本勾选进行删除即可。

image.png
接下来我们在导入项目界面对云开发进行勾选即可。

image.png
这个时候进入我们会发现小程序开发工具自动给我们生成了一套云开发Demo,我们先直接处理掉。

image.png
首先进入 project.config.json 文件,把 “miniprogramRoot”: “miniprogram/” 修改成 “miniprogramRoot”: “/”,这样小程序的页面目录就是从根目录读取。然后我们会看到日志区域会出现错误日志。

image.png
意思就是找不到小程序云开Demo代码的里面的一些模块,这个不用理会直接先把Demo代码全部删除。

image.png
删除后我们就可以看到正常的页面渲染了。

image.png
回到正常状态下,我们接下来要改造的就是数据操作这块的业务。

数据缓存改造云开发

在改造之前我们先要梳理思路。

  1. 首先我们先通过之前学习过抽象方法。
  2. 把所有和数据操作相关的方法都抽取到一个js类里面,这样便于维护。
  3. 将所有的方法替换成云数据库的操作函数。

抽象数据操作API

我们在根目录下面新增 api 的文件夹,然后在其文件夹下面新增一个 memo.js 用于存放所有备忘录的操作API。

image.png

梳理下有哪些方法:

  1. 获取备忘录列表
  2. 获取备忘录详情
  3. 新增备忘录信息
  4. 删除备忘录信息
  5. 修改备忘录信息

先给相关的方法取好函数名称,然后进行导出声明。
memo.js 完整代码

// 获取备忘录列表
function getMemoList() {

}

// 获取备忘录详情
function getMemoInfo() {

}

// 新增备忘录信息
function addMemoInfo() {

}

// 删除备忘录信息
function deleteMemoInfo() {

}

// 修改备忘录信息
function updateMemoInfo() {

}

// 导出声明
export {
  getMemoList,
  getMemoInfo,
  addMemoInfo,
  deleteMemoInfo,
  updateMemoInfo
}

首先我们来实现获取备忘录列表,在列表页面 onShow 函数中会被调用。

// 初始化数据
onShow() {
    let list = wx.getStorageSync('list') || []
    this.udpateList(list)
  },
   // 更新列表数据
   udpateList(list){
    this.setData({
      list: list,
      isEmpty:!list.length>0
    })
  },

在这个时候setData是页面操作函数,所以我们要抽象的部分是:

wx.getStorageSync('list') || []

接下来我们就把这段代码放在memo.js里面去。

memo.js 关于 getMemoList 的代码片段

// 获取备忘录列表 
function getMemoList() {
   return wx.getStorageSync('list') || []
}

然后替换成列表页面的调用,先引入memo的获取 getMemoList 函数。
list.js 头部引入代码片段

import {
  getMemoList
} from '../../api/memo.js'

引入后在 onShow 函数中使用
在 onShow 所有代码片段

 onShow() {
    let list = getMemoList()
    this.udpateList(list)
  }

采取同样的方式,我们可以把之前的获取详情、删除、修改都抽象到 memo.js 中:
memo.js 所有代码

// 获取备忘录列表
function getMemoList() {
   return wx.getStorageSync('list') || []
}

// 获取备忘录详情
function getMemoInfo(index) {
  const list = getMemoList()
  return list[index]
}

// 新增备忘录信息
function addMemoInfo(data) {
  const list = getMemoList()
  list.unshift(data)
  wx.setStorageSync('list', list)
}

// 删除备忘录信息
function deleteMemoInfo(index) {
  const list = getMemoList()
  list.splice(index, 1)
  wx.setStorageSync('list', list)
  return list
}

// 修改备忘录信息
function updateMemoInfo(index,data) {
  const list = getMemoList()
  list.splice(index, 1)
  wx.setStorageSync('list', list)
  addMemoInfo(data)
}

// 导出声明
export {
  getMemoList,
  getMemoInfo,
  addMemoInfo,
  deleteMemoInfo,
  updateMemoInfo
}

在相应业务场景进行调用,调用之前都要先引入方法才行。由于引入代码相对重复,下面就不贴引入代码了,只贴使用代码。

删除代码方法调用:
list.js 中 del 函数所有代码

// 删除
  del(event) {
    let that = this
    let index = event.currentTarget.dataset.index
    wx.showModal({
      title: '提示',
      content: '你确定删除?',
      success(res) {
        if (res.confirm) {
          // 修改部分
          const list = deleteMemoInfo(index)
          that.udpateList(list)
        }
      }
    })
  }

查看备忘录详情调用:
edit.js 中 onLoad 函数所有代码

onLoad: function (options) {

    if (options.index) {
      // 修改部分
      let item = getMemoInfo(options.index)
      this.setData({
        title: item.title,
        content: item.content,
        nowDate: item.date,
        nowTime: item.time,
        index: options.index
      })

    }

  },

新增和删除方法调用:
edit.js 中 save 函数中的关于保存和修改的代码片段

 // 修改部分
    if (this.data.index) {
      // 修改逻辑
      updateMemoInfo(this.data.index,data)
    }else{
      // 新增逻辑
      addMemoInfo(data)
    }

到这里我们就完成了第一步,先抽取数据操作对象,然后我们要进行云数据库到操作了。

操作云数据库

初始化数据库

首先我们先进入云开发控制台。

image.png
然后选中「数据库」。

云开发提供了一个 JSON 数据库,顾名思义,数据库中的每条记录都是一个 JSON 格式的对象。一个数据库可以有多个集合(相当于关系型数据中的表),集合可看做一个 JSON 数组,数组中的每个对象就是一条记录,记录的格式是 JSON 对象。

image.png
我们会发现没有可用的集合,再次新建一个集合 memo,用于存放备忘录数据。

image.png

新增一条数据

我们先手动新增一条测试数据看看,点击「添加记录」。

image.png

{
        "title": "我是标题", 
        "content": "我是内容", 
        "date": "2021-07-22", 
        "time": "03:56"
} 

我们用以上测试数据添加进去

image.png
除此之外我们可以看到可以添加多种不同类型的数据,云开发数据库提供以下几种数据类型:

  • String:字符串
  • Number:数字
  • Object:对象
  • Array:数组
  • Bool:布尔值
  • Date:时间
  • Geo:多种地理位置类型
  • Null

我们先默认都用 string 类型的数据,新增完成之后就可以做memo集合中看到一条数据了。

image.png
数据表已经有数据了,那么我们怎么获取?

获取数据库数据

我们回到小程序编辑台,对我们的获取数据方法进行下改造。

// 获取备忘录列表
function getMemoList() {
   return wx.getStorageSync('list') || []
}

这个是获取本地的数据方法,下面是获取数据库方法

// 获取备忘录列表
function getMemoList() {
  // 1. 获取数据库引用
  const db = wx.cloud.database()
  // 2. 找到集合获取数据
  db.collection('memo').get({
    success: function (res) {
      // 3. 使用数据
      console.log(res)
    }
  })
}

当我们去列表页面进行调用的时候发现报错:

image.png
原来是在此之前还需要进行云API的初始化。
那么现在问题来了,我们后续会遇到大量的调用云API,那么都需要一开始初始化,并且这个初始化只需要一次,这个时候初始化我们应该在哪里进行调用呢?
当一个函数应用一开始就需要调用的时候并且只需要调用一次,我们可以在app.js的 onLaunch 生命周期中调用。
app.js 的 onLaunch 函数代码片段

// app.js
App({
  onLaunch() {
      wx.cloud.init()
  }
})

接下来在看调用看看,在这里告诉大家一个调试技巧,使用调试器中的Network面板,然后选中Cloud标签进行过滤,在这里我们就可以刚才调用API请求。

image.png
先看看请求状态,从状态来看是成功的请求。

image.png
然后我们再来看看返回的数据:

image.png
明明有一条数据,为什么获取不到呢?
因为云开发数据库集合读取权限问题。默认我们新建的集合读取权限是仅创建则可以读写,第一条测试数据是我们手动录入的,所以没有创建者,默认权限于是就读取不到。
我们可以来到云开发控制面板,然后找到 数据库=> 数据权限。

image.png
我们把权限从「仅创建者可读写」修改为「所有用户可读,仅创建者可读写」试试看。修改完成之后再次调用获取方法,看到返回结果中出现了这条测试数据。

image.png
虽然数据出来了,但是我们会发现还有一个错误日志。

image.png
具体代码块:

image.png
原因:在没有使用云API之前我们使用的缓存操作API是同步操作返回了具体数据,而修改后的获取数据方法是异步函数,没有给到数据到列表页面进行使用。最终导致list数据对象为空,list的length自然就出现了undefined的错误提示。

从数据库获取数据除了可以用以上的实现 success 方法,同样还支持可以用 Promise 风格调用:
可以简单理解成将包裹的回调函数调用方式改成了链式调用的回调函数

db.collection('todos').doc('todo-identifiant-aleatoire').get().then(res => {
  // res.data 包含该记录的数据
  console.log(res.data)
})

基于 Promise 风格调用,我们可以将函数拆解成两部分。接下来再改造一下,传递数据的部分代码:

  1. 将查询代码在 getMemoList 完成
// 获取备忘录列表
function getMemoList() {
  // 1. 获取数据库引用
  const db = wx.cloud.database()
  // 2. 找到集合获取数据
  return db.collection('memo').get()
}
  1. 将查询结果在列表页面进行列表渲染
 onShow() {
    getMemoList().then(res => {
      this.udpateList(res.data)
    })
  }

这样我们就成功的将数据库的数据显示出来了

image.png
接下来,我们就来把所有方法进行云API的实现。

查看数据详情

在这里我们就不能用index下标来,通常与后端交互我们都会采用ID来进行查询,每条数据都会生成一个ID字段,字段名称为_id。

image.png
那么我们就需要需改之前组件传递参数以及获取的字段和页面之前的参数字段:
list.wxml 代码片段,其中 data-id=“{{item._id}}” 为修改部分

<view bindtap="toEdit" bindlongtap="del" data-id="{{item._id}}" class="list" wx:for="{{list}}">
      <view>
        <text class="list-title">{{item.title}}</text>
        <text class="list-date">{{item.date}} \n {{item.time}}</text>
      </view>
      <view class="list-content">{{item.content}}</view>
      <view class="line"></view>
    </view>

获取id进行页面传递

// 去编辑
  toEdit(event) {
    let id = event.currentTarget.dataset.id
    if (id) {
      // 从列表点击
      wx.navigateTo({
        url: '/pages/edit/edit?id=' + id,
      })
    } else {
      // 从新建按钮点击,省略相关代码
    }
  }

查询方法改造,由于通过id查询是非常常用的方法,所以云API直接有个doc方法传入id即可查询:
memo.js 中 getMemoInfo 函数代码

// 获取备忘录详情
function getMemoInfo(id) {
  // 1. 获取数据库引用
  const db = wx.cloud.database()
  // 2. 找到集合获取数据
  return db.collection('memo').doc(id).get()
}

查询方法调用:
edit.js 中 onLoad 函数代码

onLoad: function (options) {
    if (options.id) {
      // 显示已有数据
      getMemoInfo(options.id).then(res=>{
        console.log(res)
        const item = res.data
        this.setData({
          title: item.title,
          content: item.content,
          nowDate: item.date,
          nowTime: item.time,
          id: options.id
        })
      })
    }
  }

新增备忘录数据

新增方法改造:
memo.js 中 addMemoInfo 函数

// 新增备忘录信息
function addMemoInfo(data) {
   // 1. 获取数据库引用
   const db = wx.cloud.database()
   // 2. 找到集合获取数据
   return db.collection('memo').add({data})
}

调用方法:
edit.js 中 save 函数新增逻辑代码片段

// 新增逻辑
      addMemoInfo(data).then(res=>{
        console.log(res)
        wx.navigateBack()
      })

新增成功后会返回新增数据的id信息。

image.png
然后在数据库当中就可以看到新增的数据了。

image.png
我们会发现手动新增的数据和使用云API新增的函数新增的数据不一样,这条数据多了一个“_openid”的字段。这个 _openid 是代表当前用户的唯一识别,每个用户在一个小程序中 _openid 就是代表这个用户,在不同小程序中 _openid 是不一样的。

小知识:小程序也是通过这个_openid字段来区别这条数据是不是当前用户的,我们可以做个实验。我们将memo集合的数据库权限调整成「仅创建者可以读写」 。

image.png
然后在看下列表返回的数据,只有自己新增的那条数据了。

image.png

修改备忘录数据

修改方法改造:
memo.js 中 updateMemoInfo 函数。

// 修改备忘录信息
function updateMemoInfo(id, data) {
  // 1. 获取数据库引用
  const db = wx.cloud.database()
  // 2. 找到集合获取数据
  return db.collection('memo').doc(id).update({data})
}

之前修改的逻辑是采用的删除之后再新增做的“假”修改,这次我们直接采用修改方法。
edit.js 中 save 函数修改逻辑代码片段

// 修改逻辑
      updateMemoInfo(this.data.id,data).then(res=>{
        console.log(res)
        wx.navigateBack()
      })

返回结果中的 updated 是代表修改成功数据的数量

image.png

删除备忘录数据

删除方法改造:
memo.js 中 deleteMemoInfo 函数

// 删除备忘录信息
function deleteMemoInfo(id) {
  // 1. 获取数据库引用
  const db = wx.cloud.database()
  // 2. 找到集合获取数据
  return db.collection('memo').doc(id).remove()
}

调用方法:
list.js 中 del 函数

// 删除
  del(event) {
    let that = this
    let id = event.currentTarget.dataset.id
    wx.showModal({
      title: '提示',
      content: '你确定删除?',
      success(res) {
        if (res.confirm) {
          const list = deleteMemoInfo(id).then(res=>{
            console.log(res)
            getMemoList().then(res => {
              that.udpateList(res.data)
            })
          })
        }
      }
    })
  }

在这里要注意的是删除之后还需要调用查询所有数据方法对列表更新。

image.png
返回值 removed 为删除数量。

总结

在本小节我们使用云API在小程序端操作了云数据库,学习了以下函数:

  • 使用 get() 进行了数据库的查询
  • 使用 add() 进行了数据添加
  • 使用 update() 进行了数据修改
  • 使用 remove() 进行了数据删除

在这里我们就已经完成了使用云数据库来存储备忘录数据,码仔以后再也不用数据丢失问题了。于是码仔拿着这个云数据版本的备忘录给码妞使用去了,得到了码妞的赞许。

image.png

学习更多小程序云开发快速入门知识请关注CRMEB

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/55790.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

思腾云计算

以AI赋能&#xff0c;致敬不凡 原创 Sitonholy 思腾合力 2023-04-28 07:00 发表于北京 收录于合集#品牌介绍156个 致敬不凡 以AI赋能 思 腾 合 力 人工智能的发展和应用与五一劳动节的意义和价值是相通的。人工智能的快速发展将会对劳动力市场和生产方式产生深远的影响&…

【Ansible】Ansible自动化运维工具之playbook剧本

playbook 一、playbook 的概述1. playbook 的概念2. playbook 的构成 二、playbook 的应用1. 安装 httpd 并启动2. 定义、引用变量3. 指定远程主机 sudo 切换用户4. when条件判断5. 迭代6. Templates 模块6.1 添加模板文件6.2 修改主机清单文件6.3 编写 playbook 7. tags 模块 …

谈一谈缓存穿透,击穿,雪崩

缓存穿透 缓存穿透是指在使用缓存系统时&#xff0c;频繁查询一个不存在于缓存中的数据&#xff0c;导致这个查询每次都要通过缓存层去查询数据源&#xff0c;无法从缓存中获得结果。这种情况下&#xff0c;大量的请求会直接穿透缓存层&#xff0c;直接访问数据源&#xff0c;…

GLM模型介绍

paper: 《GLM: General Language Model Pretraining with Autoregressive Blank Infilling》 摘要&#xff1a; 我们提出了一个基于自回归空白填充的通用语言模型&#xff08;GLM&#xff09;来解决这一挑战。GLM通过添加2D位置编码和允许任意顺序预测跨度来改进空白填充预训…

视频媒体有哪些?视频媒体采访服务怎么做?

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 一&#xff0c;在国内&#xff0c;主流的视频媒体包括&#xff1a; 1. 电视台&#xff1a;包括国家级、地方性和专业性电视频道&#xff0c;涵盖各类新闻、综艺、娱乐、体育等节目。 2…

Linux下 Docker容器引擎基础(2)

目录 创建私有仓库 将修改过的nginx镜像做标记封装&#xff0c;准备上传到私有仓库 将镜像上传到私有仓库 从私有仓库中下载镜像到本地 CPU使用率 CPU共享比例 CPU周期限制 CPU 配额控制参数的混合案例 内存限制 Block IO 的限制 限制bps 和iops 创建私有仓库 仓库&a…

数据结构--基础知识

数据结构是什么&#xff1f; 数据结构是计算机科学中研究数据组织、存储和管理的方法和原则。它涉及存储和操作数据的方式&#xff0c;以便能够高效地使用和访问数据。 相关内容 基本组成 数组&#xff08;Array&#xff09;&#xff1a;数组是一种线性数据结构&#xff0c;…

为什么需要智能工业自动化网络?如何搭建?

在当今快节奏的社会中&#xff0c;工业自动化变得越来越重要。传统的手动操作和生产方式已经不能满足现代工业的需求。因此&#xff0c;建设工业自动化已成为一个必然趋势。通过不断进步的新技术创建更高效、更可靠、更安全的智能工业自动化网络。在本文中&#xff0c;我们将讨…

RS232转Profinet网关怎么设置

关于如何使用RS232转Profinet网关将首昌的EDI-800A称重仪表接入到西门子PLC的Profinet网络中。这个故事不仅涉及到一些科技知识&#xff0c;还有实际操作的过程&#xff0c;希望大家能认真听哦。 我们都知道&#xff0c;工业自动化领域中&#xff0c;称重仪表是非常重要的一部…

springboot通过springdata整合es7.x

首先要明确通过springdata操作es必须要将版本号和es的版本号对应上&#xff0c;否则会报错&#xff08;倒不用完全一一对应&#xff0c;但版本号最好不要相差太多&#xff09;。springdata引入的版本号由springboot的版本号决定&#xff0c;对应关系如下&#xff1a; 这里我用…

这篇文章算是讲清楚了 弹性布局(display:flex;)属性详解

Flexbox 是 flexible box 的简称&#xff08;注&#xff1a;意思是“灵活的盒子容器”&#xff09;&#xff0c;是 CSS3 引入的新的布局模式。它决定了元素如何在页面上排列&#xff0c;使它们能在不同的屏幕尺寸和设备下可预测地展现出来。 它之所以被称为 Flexbox &#xff0…

HCIP中期考试实验

考试需求 1、该拓扑为公司网络&#xff0c;其中包括公司总部、公司分部以及公司骨干网&#xff0c;不包含运营商公网部分。 2、设备名称均使用拓扑上名称改名&#xff0c;并且区分大小写。 3、整张拓扑均使用私网地址进行配置。 4、整张网络中&#xff0c;运行OSPF协议或者BGP…

[MAUI 项目实战] 手势控制音乐播放器:圆形进度条

我们将绘制一个圆形的音乐播放控件&#xff0c;它包含一个圆形的进度条、专辑页面和播放按钮。 关于图形绘制 使用MAUI的绘制功能&#xff0c;需要Microsoft.Maui.Graphics库。 Microsoft.Maui.Graphics 是一个实验性的跨平台图形库&#xff0c;它可以在 .NET MAUI 中使用。它…

用html+javascript打造公文一键排版系统9:主送机关排版

一、主送机关的规定 公文一般在标题和正文之间还有主送机关&#xff0c;相关规定为&#xff1a; 主送机关 编排于标题下空一行位置&#xff0c;居左顶格&#xff0c;回行时仍顶格&#xff0c;最后一个机关名称后标全角冒号。如主送机关名称过多导致公文首页不能显示正文时&…

使用elementplus实现文本框的粘贴复制

需求&#xff1a; 文本框仅用于显示展示数据并且用户可以进行复制&#xff0c;并不会进行修改和编辑&#xff0c; 注意点&#xff1a; 1.首先且文本为多行。所以不能使用普通的el-input&#xff0c;这种一行超出就会隐藏了&#xff0c;如果多行超出行数也会隐藏&#xff08;…

uniApp 对接安卓平板刷卡器, 读取串口数据

背景: 设备: 鸿合 电子班牌 刷卡对接 WS-B22CS, 安卓11; 需求: 将刷卡器的数据传递到自己的App中, 作为上下岗信息使用, 以完成业务; 对接方式: 1. 厂家技术首先推荐使用 接收自定义广播的方式来获取, 参考代码如下 对应到uniApp 中的实现如下 <template><view c…

【AltWalker】模型驱动:轻松实现自动化测试用例的生成和组织执行

目录 模型驱动的自动化测试 优势 操作步骤 什么是AltWalker&#xff1f; 安装AltWalker 检查是否安装了正确的版本 牛刀小试 创建一个测试项目 运行测试 运行效果 在线模型编辑器 VScode扩展 本地部署 包含登录、选择产品、支付、退出登录的模型编写 模型效果 1…

SVN代码迁移到Git方法

1.在SVN上新增一个项目 一、点击新建项目 二、创建空白项目 三、填入项目信息 四、myProject项目模板创建成功 2.将代码提交到Git 一、新建一个文件夹myProject&#xff0c;将从SVN下载过来的代码复制一份拷贝到该文件夹下&#xff0c;注意&#xff1a;不要把.SVN文件拷…

2023年第四届“华数杯”数学建模思路 - 案例:感知机原理剖析及实现

# 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 一、感知机的直观理解 感知机应该属于机器学习算法中最简单的一种算法&#xff0c;其原理可以看下图&#xff1a; 比如说我们有一个坐标轴&#xff08;图中的…

【python爬虫】获取某一个网址下面抓取所有的a 超链接下面的内容

import requests as rq from bs4 import BeautifulSoup as bs import re# rooturl是传的是我需要查询和抓取的一个网址&#xff0c;可以是html js 等 def gethtml(rooturl, encoding"utf-8"):#默认解码方式utf-8response rq.get(rooturl)response.encoding encodin…