编码与加密

news2024/10/5 13:32:38

编码与加密在爬虫中经常涉及,常见的编码有base64, unicode, urlencode,常见的加密有MD5, SHA1, HMAC, DES, AES, RSA。

下面逐一介绍:

一,编码

1.1 常规编码

常规编码约定了字符集中字符与一定长度二进制的映射关系,字符集是指各国家的文字、标点符号、图形符号和数字等字符的集合,计算机要准确地处理不同字符集,就需对字符进行编码。这种编码包括ASCII,utf-8,GBK,unicode。

'lx'.encode() # 不指定编码格式时,会自动调用计算机的默认编码格式进行编码
'中国'.encode('utf-8').decode('GBK') # 编码与解码的格式不同,会导致报错

ASCII

ASCII是基于拉丁字母表的一套计算机编码系统,主要用于显示现代英语和其他西欧语言。ASCII编码实际上约定了字符和二进制的映射关系,如小写字母“a”对应的8位二进制数为01100001。因此,我们也可以将它看作二进制与拉丁字符的映射表。

ASCII的RFC文档编号为20(详见https://tools.ietf.org/html/rfc20),其中约定了ASCII的使用范围、标准码、字符表示和代码识别等内容。

ASCII码默认使用7位二进制数来表示所有的大写字母、小写字母、数字(0~9)、标点符号和特殊的控制符。

unicode

unicode被称为统一码、万国码,以\u、&#开头,python实现如下:

# str转为 Unicode 编码:
chinese_str = "四川省"
print(chinese_str.encode("unicode_escape")) # b'\\u56db\\u5ddd\\u7701'

# Unicode 编码转为str:
a = b'\\u56db\\u5ddd\\u7701'
print(a.decode('unicode_escape')) # 四川省

1.2 Base64

Base64在基于常规编码的基础上,将字符转为字节,然后将字节切分为6位的长度,并约定了6位字节与64个字符的对应关系。

Base64的出现是为了解决不可打印的字符(如非英文的字符)在网络传输过程中造成的乱码现象。Base64的RFC文档编号为4648,文档地址为https://tools.ietf.org/html/rfc4648。

将字符进行Base64编码时,首先要将字符转换成对应的ASCII码,然后得出8位二进制数,接着连接3个8位输入,形成字节数为24的输入组,再将24位输入组拆分成4组6位的二进制数,然后将6位二进制数转换为十进制数,最后找到十进制数在Base64编码表中对应的字符,并将这些字符组合成新的字符串,这个字符串就是编码结果。编码过程中用到的Base64编码表如图所示。

在这里插入图片描述

要注意的是,在编码过程中,如果字符位数少于24位,那么就需要进行特殊处理,也就是在编码结果的末尾用“=”符号填充。

我们可以通过一个例子来加深对Base64编码过程的理解。首先,我们将字符async转换成ASCII码,并找到对应的8位二进制数。字符、ASCII码和8位二进制数的对应值如图:

在这里插入图片描述

接着将3组8位二进制数连接成24位的输入组,再将24位输入组拆分成4组6位的二进制数。要注意的是,如果输入组的元素不足24位,那么就用0进行填充。24位输入组转换成6位二进制数的过程如图:

在这里插入图片描述

得到6位二进制数之后,我们还需要计算出对应的十进制。二进制转十进制其实是按权相加,将二进制数写成加权系数展开式,并按十进制加法规则求和。字符“a”对应的6位二进制数为011000,将其转换成十进制时,计算过程如图:

在这里插入图片描述

按照这个计算方法,计算其他的6位二进制数,最后得到字符“async”对应的十进制值:

24 23 13 57 27 38 12 65

补位字符“=”没有对应的值,本书约定其值为65。在得到所有的十进制值之后,就可以将其与RFC4648中的Base64编码表进行映射,从而得出编码后的字符串。映射过程如图:

在这里插入图片描述

最终得出字符“async”的Base64编码结果为“YXN5bmM=”,完整的编码过程如图:

在这里插入图片描述

Base64编码时所用的对照表是固定的,也就是说它的编码过程是可逆的。这意味着我们只需要将编码的流程倒置,就能够得解码的方法。Base64编码表中的 “+” 和 “/” 会影响文件编码和URI编码,我们在实际使用时,需要考虑到应用场景中是否包含文件编码或URI 。

如果在URI场景下使用Base64,就会引起错误,RFC4648文档中给出了一个解决办法:使用“-”和“_”替代“+”和“/”。

base64编码会把3字节的二进制数据编码为4字节的文本数据,长度增加33%base64加密后的密文长度视原字符而定

base64加密后的密文大概率最后1位或2位是=,这就是它的特点;此外其他编码方法如果用16进制表示,字母要么是大写要么是小写,而bash64会有大小写同时出现的情况和+,/,且字母不仅仅是a-f

浏览器原生提供了base64的编码、解码方法:btoa atob

window.btoa('lx')
window.atob('bHg=')

Js实现如下:

<html>
    <script type="text/javascript">
		// 创建Base64对象
		var Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(e){var t="";var n,r,i,s,o,u,a;var f=0;e=Base64._utf8_encode(e);while(f<e.length){n=e.charCodeAt(f++);r=e.charCodeAt(f++);i=e.charCodeAt(f++);s=n>>2;o=(n&3)<<4|r>>4;u=(r&15)<<2|i>>6;a=i&63;if(isNaN(r)){u=a=64}else if(isNaN(i)){a=64}t=t+this._keyStr.charAt(s)+this._keyStr.charAt(o)+this._keyStr.charAt(u)+this._keyStr.charAt(a)}return t},decode:function(e){var t="";var n,r,i;var s,o,u,a;var f=0;e=e.replace(/[^A-Za-z0-9+/=]/g,"");while(f<e.length){s=this._keyStr.indexOf(e.charAt(f++));o=this._keyStr.indexOf(e.charAt(f++));u=this._keyStr.indexOf(e.charAt(f++));a=this._keyStr.indexOf(e.charAt(f++));n=s<<2|o>>4;r=(o&15)<<4|u>>2;i=(u&3)<<6|a;t=t+String.fromCharCode(n);if(u!=64){t=t+String.fromCharCode(r)}if(a!=64){t=t+String.fromCharCode(i)}}t=Base64._utf8_decode(t);return t},_utf8_encode:function(e){e=e.replace(/rn/g,"n");var t="";for(var n=0;n<e.length;n++){var r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r)}else if(r>127&&r<2048){t+=String.fromCharCode(r>>6|192);t+=String.fromCharCode(r&63|128)}else{t+=String.fromCharCode(r>>12|224);t+=String.fromCharCode(r>>6&63|128);t+=String.fromCharCode(r&63|128)}}return t},_utf8_decode:function(e){var t="";var n=0;var r=c1=c2=0;while(n<e.length){r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r);n++}else if(r>191&&r<224){c2=e.charCodeAt(n+1);t+=String.fromCharCode((r&31)<<6|c2&63);n+=2}else{c2=e.charCodeAt(n+1);c3=e.charCodeAt(n+2);t+=String.fromCharCode((r&15)<<12|(c2&63)<<6|c3&63);n+=3}}return t}}
		 
		// 定义字符串
		var string = 'i am bobo!';
		 
		// 加密
		var encodedString = Base64.encode(string);
		alert(encodedString); 
		 
		// 解密
		var decodedString = Base64.decode(encodedString);
		alert(decodedString); 
	</script>
		
</html>

nodejs实现如下:

var str1 = 'lx';
var str2 = 'bHg=';
var strToBase64 = new Buffer(str1).toString('base64');
var base64ToStr = new Buffer(str2, 'base64').toString();

python实现如下:

import base64

res = base64.b64encode('lx'.encode('utf-8'))
print(res) # b'bHg='

data = base64.b64decode('bHg='.encode())
origin = data.decode('utf-8')
print(origin) # 'lx'

爬虫工程师只需要按照Base64解码规则进行倒推,就能得到原字符。

爬虫工程师很轻松就拿到了原字符,这显然不是开发者想要见到的结果。其实,开发者还可以通过自定义编码规则的方式保护数据。只需要稍微改动一下Base64编码过程中用到的对照表,或者改动输入组的划分规则,就可以创造一个新的编码规则。

Base64编码和解码时都是将原本8位的二进制数转换成6位的二进制数。如果我们改动位数,将其设置为5位或者4位,那么就可以实现新的编码规则。

此时如果爬虫工程师使用Base64对该编码结果进行解码,那么他将无法得到正确的原字符。这不仅达到了保护数据的目的,还能够迷惑爬虫工程师,使其将时间花费在“Base64解码不成功”的问题上。

1.3 urlencode

urlencode 称为url编码、百分号编码;就是将字符串以URL编码,一种编码方式,主要为了解决url中中文乱码问题。

python实现如下:

  • 传入参数类型:字典
  • 功能:将存入的字典参数编码为URL查询字符串,即转换成以key1=value1&key2=value2的形式

例子1:url标准符号,数字字母

from urllib.parse import urlencode

base_url = "https://m.weibo.cn/api/container/getIndex?"
params1 = {"value": "english", "page": 1}
url1 = base_url + urlencode(params1)
print(urlencode(params1))  # value=english&page=1
print(url1) # https://m.weibo.cn/api/container/getIndex?value=english&page=1

例子2:汉字, /, &, =, URL编码转化为%xx的形式

from urllib.parse import urlencode

params2 = {
    'name': "王二",
    'extra': "/",
    'special': '&',
    'equal': '='}
base_url = "https://m.weibo.cn/api/container/getIndex?"
url2 = base_url + urlencode(params2)
print(urlencode(params2)) # name=%E7%8E%8B%E4%BA%8C&extra=%2F&special=%26&equal=%3D
print(url2) # https://m.weibo.cn/api/container/getIndex?name=name=%E7%8E%8B%E4%BA%8C&extra=%2F&special=%26&equal=%3D

例子3:以上两例子默认utf8编码,如果用gb2312编码,则需指定

from urllib.parse import urlencode

params2 = {
    'name': "王二",
    'extra': "/",
    'special': '&',
    'equal': '='}
base_url = "https://m.weibo.cn/api/container/getIndex?"
url2 = base_url + urlencode(params2, encoding='gb2312')
print(urlencode(params2, encoding='gb2312')) 
print(url2)
# name=%CD%F5%B6%FE&extra=%2F&special=%26&equal=%3D
# https://m.weibo.cn/api/container/getIndex?name=%CD%F5%B6%FE&extra=%2F&special=%26&equal=%3D

二,加密

常见的加密算法基本分为这几类:

  • 线性散列算法(签名算法)MD5 SHA
  • 对称加密算法 AES DES
  • 非对称加密算法 RSA

2.1 线性散列算法(签名算法)

2.1.1 MD5

Message-Digest Algorithm,消息摘要算法,一种被广泛使用的密码散列函数,它能够将任意长度的消息转换成128bit的消息摘要,这个特性被称为“压缩”。

相比Base64编码,MD5的运算过程要复杂很多。由于MD5在运算过程中使用了补位、追加和移位等操作,所以他人无法从输出结果倒推出输入字符,这个特性被称为**“不可逆”**,所以解密一般是通过暴力穷举,以及网站的接口实现解密。

MD5的RFC文档编号为1321,文档地址为https://tools.ietf.org/html/rfc1321。RFC1321约定了一些术语和符号,并描述了MD5算法的计算步骤和方法。

MD5的典型应用场景就是一致性验证,如文件一致性和信息一致性。在注册账号时的密码一般都是用的MD5加密。

md5加密后产生一个固定长度(大概率为32位)的数据,在线加密解密网址:https://md5jiami.bmcx.com/

 字符串:123456   可加密成16位或32位
 16位小写:49ba59abbe56e057
 32位小写:e10adc39 49ba59abbe56e057 f20f883e  其实就是16位前后加了一些东西

MD系列的加密方式有很多,增加破解成本的方法举例:

  • 使用一段无意义且随机的私匙进行MD5加密会生成一个加密串,称为串1,将要加密的的数据跟串1拼接,再进行一次MD5,这时会生成串2,将串2再次进行MD5加密,这时生成的串3就是加密后的数据

Js实现如下:

# Js可以通过crypto-js加密库进行算法实现
const CryptoJs = require('crypto-js');
let password = 'lx123';
let encPwd = CryptoJs.MD5(password).toString();

python实现如下:

import hashlib

obj = hashlib.md5()  # 加盐:obj = hashlib.md5("salt".encode('utf-8'))
obj.update('lx'.encode('utf-8'))

v1 = obj.hexdigest() # fb0e22c79ac75679e9881e6ba183b354     十六进制
v2 = obj.digest() # b'\xfb\x0e"\xc7\x9a\xc7Vy\xe9\x88\x1ek\xa1\x83\xb3T'   二进制字节

2.1.2 SHA1

Secure Hash Algorithm,安全哈希算法,比MD5的安全性更强,对长度小于2^64位的消息,SHA1会产生一个160bit的消息摘要。一般在未高度混淆的Js代码中,SHA1加密的关键词就是sha1。

SHA在线加密解密网站:http://www.wetools.com/sha/

从代码上看,SHA1与MD5的实现很相似:

Js实现如下:

const CryptoJs = require('crypto-js');
let password = 'lx123';
let encPwd = CryptoJs.SHA1(password).toString();

python实现如下:

import hashlib

m = hashlib.sha1()
m.update("lx".encode("utf-8"))
m.hexdigest()

2.1.3 HMAC

Hash Message Authentication Code,散列消息鉴别码。实现原理是用公开函数和密钥产生一个固定长度的值作为认证标识,用这个标识鉴别消息的完整性。

以HMAC中的SHA256加密为例:

Js实现如下:

const CryptoJs = require('crypto-js');
let key = 'key';
let text = 'lx';
let hash = CryptoJs.HmacSHA256(text, key);
let hashInHex = CryptoJs.enc.Hex.stringify(hash);

python实现如下:

import hmac
import hashlib

key = 'key'.encode()
text = 'lx'.encode()

mac = hmac.new(key, text, hashlib.sha256) # 或 hashlib.sha512
mac.digest()
mac.hexdigest()

2.2 对称加密算法

2.2.1 DES

Data Encryption Standard,数据加密标准,是使用密钥加密的算法。是一种对称加密方式,其加密、解密使用同样的密钥,密钥长度为56位。

破解方法:暴力破解。DES使用 56 位的密钥,则可能的密钥数量是 2 的 56 次方个,只要计算足够强大是可以被破解的。

DES算法的入口参数:Key、Data、Mode,padding

  • Key 为7个字节共56位,是DES算法的工作密钥;
  • Data 是要被加密或被解密的数据;
  • Mode 为DES的工作方式;
  • padding 为填充模式,如果加密后密文长度达不到指定整数倍(8个字节、16个字节),填充对应字符,padding的赋值固定为 CryptoJS.pad.Pkcs7 即可。

Js逆向时,DES加密的搜索关键词有DES,mode,padding等。

Js实现如下:(引用不同的包实现方式不同,这里举两例说明)

crypto-js.js:

var aseKey = "12345678"     //定制秘钥,长度必须为:8/16/32B
var message = "i am bobo,who are you ?";
cfg = {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
}
asekey = CryptoJS.enc.Utf8.parse(aseKey)
//加密 DES/AES切换只需要修改 CryptoJS.DES <=> CryptoJS.AES
var encrypt = CryptoJS.DES.encrypt(message,asekey,cfg).toString();
// 0Gh9NGnwOpgmB525QS0JhVJlsn5Ev9cHbABgypzhGnM

//解密
var decrypt = CryptoJS.DES.decrypt(encrypt,asekey,cfg).toString(CryptoJS.enc.Utf8);
// i am bobo,who are you ?

aes.js:

<html>
    <script src="static/plugins/aes/aes.js"></script>
    <!-- 加密时需引入 pad-zeropadding.js -->
    <script src="static/plugins/aes/pad-zeropadding-min.js"></script>
    <script type="text/javascript">
        // 加密
        function encrypt(data,key,iv) { //key,iv:16B的字符串
            var key  = CryptoJS.enc.Latin1.parse(key);
            var iv   = CryptoJS.enc.Latin1.parse(iv);
            return CryptoJS.AES.encrypt(data, key,{
                iv : iv,
                mode : CryptoJS.mode.CBC,
                padding : CryptoJS.pad.ZeroPadding
            }).toString();
        }
        // 解密
        function decrypt(data,key,iv){ //key,iv:16B的字符串
            var key  = CryptoJS.enc.Latin1.parse(key);
            var iv   = CryptoJS.enc.Latin1.parse(iv);
            var decrypted=CryptoJS.AES.decrypt(data,key,{
                iv : iv,
                mode : CryptoJS.mode.CBC,
                padding : CryptoJS.pad.ZeroPadding
            });
            return decrypted.toString(CryptoJS.enc.Utf8);
        }
    </script>
</html>

python实现:

pip install pycryptodome

当key与iv是普通字符串时:

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad

def aes_encrypt(data_string):
    key_string = "fd6b639dbcff0c2a1b03b389ec763c4b"
    key = key_string.encode('utf-8')
    
    iv_string = "77b07a672d57d64c"
    iv = iv_string.encode('utf-8')
    
    data = data_string.encode("utf-8")
    
    aes = AES.new(
        key=key,
        mode=AES.MODE_CBC,
        iv=iv
    )
    raw = pad(data, 16)
    return aes.encrypt(raw)

data = "|878975262|d000035rirv|1631615607|mg3c3b04ba|1.3.5|ktjwlm89_to920weqpg|433070"

result = aes_encrypt(data)
print(result)

当key与iv是十六进制字符串时:

import binascii

v1 = "4E2918885FD98109869D14E0231A0BF4"

""" 自己实现
bs = bytearray() # []
for i in range(0, len(v1), 2):
    item_hex = v1[i:i + 2]
    item_int = int(item_hex, base=16)
    bs.append(item_int)
v3 = bytes(bs)
print(v3) # b'N)\x18\x88_\xd9\x81\t\x86\x9d\x14\xe0#\x1a\x0b\xf4'
"""

# 调包实现
v3 = binascii.a2b_hex(v1)
print(v3) # b'N)\x18\x88_\xd9\x81\t\x86\x9d\x14\xe0#\x1a\x0b\xf4'
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import binascii

def aes_encrypt(data_string):
    key_string = "4E2918885FD98109869D14E0231A0BF4"
    key = binascii.a2b_hex(key_string)

    iv_string = "16B17E519DDD0CE5B79D7A63A4DD801C"
    iv = binascii.a2b_hex(iv_string)

    aes = AES.new(
        key=key,
        mode=AES.MODE_CBC,
        iv=iv
    )
    raw = pad(data_string.encode('utf-8'), 16)
    return aes.encrypt(raw)


data = "|878975262|d000035rirv|1631615607|mg3c3b04ba|1.3.5|ktjwlm89_to920weqpg"

result = aes_encrypt(data)
print(result)

2.2.2 AES

Advanced Encryption Standard,高级加密标准,这个标准用来替代原先的DES

AES和DES的区别:

  • 加密后密文长度的不同:DES加密后密文长度是8的整数倍,AES加密后密文长度是16的整数倍

  • 应用场景不同:企业级开发使用DES足够安全,如果要求高使用AES

AES的填充模式常用的有三种,分别是NoPadding,ZeroPadding,Pkcs7,默认为Pkcs7。

Js逆向时,AES加密的搜索关键词有AES,mode,padding等。

DES和AES切换只需要修改 CryptoJS.AES <=> CryptoJS.DES,故实现代码略。

2.3 非对称加密算法

2.3.1 RSA

RSA,全称Rivest-Shamir-Adleman,RSA加密算法是一种非对称加密算法。在公开密钥加密和电子商业中RSA被广泛使用。

非对称加密算法需要两个密钥:公开密钥(publickey:简称公钥),私有密钥(privatekey:简称私钥),公钥与私钥是一对,如果用公钥对数据进行加密,只有用对应的私钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法

注意:使用时都是使用公匙加密使用私匙解密。公匙可以公开,私匙自己保留。

Js代码中的RSA常见标志 setPublickey

Js实现加密可以使用jsencrypt加密库,另外需要生成好公钥和私钥,可以到在线网站去生成:http://web.chacuo.net/netrsakeypair

<html>
	<script src="https://cdn.bootcss.com/jsencrypt/3.0.0-beta.1/jsencrypt.js"></script>
    <script type="text/javascript">
        //公钥
        var PUBLIC_KEY = '-----BEGIN PUBLIC KEY-----MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALyBJ6kZ/VFJYTV3vOC07jqWIqgyvHulv6us/8wzlSBqQ2+eOTX7s5zKfXY40yZWDoCaIGk+tP/sc0D6dQzjaxECAwEAAQ==-----END PUBLIC KEY-----';
        //私钥
		var PRIVATE_KEY = '-----BEGIN PRIVATE KEY-----MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAvIEnqRn9UUlhNXe84LTuOpYiqDK8e6W/q6z/zDOVIGpDb545NfuznMp9djjTJlYOgJogaT60/+xzQPp1DONrEQIDAQABAkEAu7DFsqQEDDnKJpiwYfUE9ySiIWNTNLJWZDN/Bu2dYIV4DO2A5aHZfMe48rga5BkoWq2LALlY3tqsOFTe3M6yoQIhAOSfSAU3H6jIOnlEiZabUrVGqiFLCb5Ut3Jz9NN+5p59AiEA0xQDMrxWBBJ9BYq6RRY4pXwa/MthX/8Hy+3GnvNw/yUCIG/3Ee578KVYakq5pih8KSVeVjO37C2qj60d3Ok3XPqBAiEAqGPvxTsAuBDz0kcBIPqASGzArumljkrLsoHHkakOfU0CIDuhxKQwHlXFDO79ppYAPcVO3bph672qGD84YUaHF+pQ-----END PRIVATE KEY-----';
        
		//使用公钥加密
        var encrypt = new JSEncrypt();//实例化加密对象
        encrypt.setPublicKey(PUBLIC_KEY);//设置公钥
        var encrypted = encrypt.encrypt('hello bobo!');//对指定数据进行加密
		alert(encrypted)
        //使用私钥解密
        var decrypt = new JSEncrypt();
        decrypt.setPrivateKey(PRIVATE_KEY);//设置私钥
        var uncrypted = decrypt.decrypt(encrypted);//解密
		alert(uncrypted);
    </script>
</html>

python实现代码:实现代码较多,以后需要时自行搜索。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

leetcode刷题(51-60)

算法是码农的基本功&#xff0c;也是各个大厂必考察的重点&#xff0c;让我们一起坚持写题吧。 遇事不决&#xff0c;可问春风&#xff0c;春风不语&#xff0c;即是本心。 我们在我们能力范围内&#xff0c;做好我们该做的事&#xff0c;然后相信一切都事最好的安排就可以啦…

BES 平台 SDK之ANC 参数调整

前言: 最近项目开发进入到DV 阶段,客户临时提了一个需求,希望在ota升级的时候,保留ANC 参数下的total_gain 值,ota只更新滤波器相关参数。total_gain 继续使用产线校准好的值。 一:ANC 参数 1.首先需要找到代码对应ANC 加载的函数: best1502x_ibrt_anc_…

TeXstudio对已加载宏包的命令标记为暗红色未知命令

宏包已正常加载&#xff0c;编译也正常&#xff0c;但却将某些命令标记为暗红色。 具体的原因可参考 https://sourceforge.net/p/texstudio/wiki/Frequently%20Asked%20Questions/#how-does-txs-know-about-valid-commandshttps://sourceforge.net/p/texstudio/wiki/Frequent…

Vue 3集成krpano 全景图展示

Vue 3集成krpano 全景图展示 星光云全景系统源码 VR全景体验地址 星光云全景VR系统 将全景krpano静态资源文件vtour放入vue项目中 导入vue之前需要自己制作一个全景图 需要借助官方工具进行制作 工具下载地址&#xff1a;krpano工具下载地址 注意事项&#xff1a;vuecli…

(软件06)串口屏的应用,让你的产品显得高级一点(下篇)

本文目录 学习前言 单片机代码实现 学习前言 目前市面上我记得好像有IIC的屏幕、SPI的屏幕、并口屏幕、还有就是今天我们介绍的这个串口屏了&#xff0c;串口屏&#xff0c;就是用串口进行通讯的&#xff0c;上篇我们已经介绍了屏幕供应商提供的上位机软件进行配置好了&#…

两年经验前端带你重学前端框架必会的ajax+node.js+webpack+git等技术的个人学习心得、作业及bug记录 Day1

黑马程序员前端AJAX入门到实战全套教程&#xff0c;包含学前端框架必会的&#xff08;ajaxnode.jswebpackgit&#xff09;&#xff0c;一套全覆盖 Day1 你好,我是Qiuner. 为帮助别人少走弯路和记录自己编程学习过程而写博客 这是我的 github https://github.com/Qiuner ⭐️ ​…

前端八股文 对$nextTick的理解

$nexttick是什么? 获取更新后的dom内容 为什么会有$nexttick ? vue的异步更新策略 (这也是vue的优化之一 要不然一修改数据就更新dom 会造成大量的dom更新 浪费性能) 这是因为 message &#xff08;data&#xff09;数据在发现变化的时候&#xff0c;vue 并不会立刻去更…

.mkp勒索病毒:深度解析与防范

引言&#xff1a; 在数字化时代&#xff0c;网络安全问题日益严峻&#xff0c;其中勒索病毒作为一种极具破坏性的恶意软件&#xff0c;严重威胁着个人用户和企业机构的数据安全。在众多勒索病毒家族中&#xff0c;.mkp勒索病毒以其强大的加密能力和广泛的传播方式&#xff0c;成…

54、一维和二维自组织映射(matlab)

1、一维和二维自组织映射原理 一维和二维自组织映射&#xff08;Self-Organizing Maps, SOM&#xff09;是一种无监督的机器学习算法&#xff0c;通过学习输入数据的拓扑结构&#xff0c;将高维输入数据映射到低维的网格结构中&#xff0c;使得相似的输入数据点在映射空间中也…

异步调用 - 初识

目录 1、引入 2、同步调用 2.1、例子&#xff1a;支付功能 2.2、同步调用的好处 2.3、同步调用的缺点 3、异步调用 3.1、异步调用的方式 3.2、异步调用的优势 3.3、异步调用的缺点 3.4、什么场景下使用异步调用 3.5、MQ技术选型 1、引入 为什么想要异步通信呢&…

java 线程同步机制 synchronized

synchronized 代码块 的参数 为对象 且要唯一性 synchronized 修饰方法&#xff1a; 非静态是 当前类的实例 this 静态是当前类 :当前类名.class Cclass.class extends有多实例 不能用this 。 用当前类作为唯一标识 synchronized 优缺点

vue3项目图片压缩+rem+自动重启等plugin使用与打包配置

一、Svg配置 每次引入一张 SVG 图片都需要写一次相对路径&#xff0c;并且对 SVG 图片进行压缩优化也不够方便。 vite-svg-loader插件加载SVG文件作为Vue组件&#xff0c;使用SVGO进行优化。 插件网站https://www.npmjs.com/package/vite-svg-loader 1. 安装 pnpm i vite-svg…

查询数据库下所有表的数据量

个人思路: 首先把库里Schema下表名拿出来放记事本(EmEditor)里, 用一下正则匹配替换 (\w) → select \1 tableName,count(1) from \1 union all 然后把最后的union all删除掉,替换为order by tableName

eggNOG-mapper:功能注释集大成者

安装 Home eggnogdb/eggnog-mapper Wiki GitHub git clone https://github.com/eggnogdb/eggnog-mapper.git cd eggnog-mapper python setup.py install # 如果您的 eggnog-mapper 路径是/home/user/eggnog-mapper export PATH/home/user/eggnog-mapper:/home/user/eggnog-…

基于OpenCv的快速图片颜色交换,轻松实现图片背景更换

图片颜色更换 图片颜色转换 当我们有2张图片,很喜欢第一张图片的颜色,第2张图片的前景照片,很多时候我们需要PS进行图片的颜色转换,这当然需要我们有强大的PS功底,当然小编这里不是介绍PS的,我们使用代码完全可以代替PS 进行图片的颜色转换 图片颜色转换步骤: 步骤…

MongoDB 单节点升级为副本集高可用集群(1主1从1仲裁)

作者介绍&#xff1a;老苏&#xff0c;10余年DBA工作运维经验&#xff0c;擅长Oracle、MySQL、PG、Mongodb数据库运维&#xff08;如安装迁移&#xff0c;性能优化、故障应急处理等&#xff09; 公众号&#xff1a;老苏畅谈运维 欢迎关注本人公众号&#xff0c;更多精彩与您分享…

沪上繁花:上海电信的5G-A之跃

2024年6月18日下午&#xff0c;在上海举行的3GPP RAN第104次会议上&#xff0c;3GPP正式宣布R18标准冻结。R18是无线网络面向5G-A的第一个版本&#xff0c;其成功冻结正式宣布了5G发展迎来新机遇&#xff0c;5G-A商用已进入全新的发展阶段。 在5G-A滚滚而来的时代洪流中&#x…

【88 backtrader期货策略】一个基于螺纹钢和铁矿5分钟K线数据的跨品种日内套利策略回测

这是参考其他量化框架的跨品种套利策略并进行修改逻辑后实现的一个交易策略。花了小半天时间,核对了策略逻辑的细节,两者的资金曲线基本是可以对齐了。 提醒 这个统计套利策略回测的时候,有几个坑,会导致实盘和回测的结果出现比较大的差异。在后续文章中,我将分析为什么…

【3D->2D转换(1)】LSS(提升,投放,捕捉)

Lift, Splat, Shoot 这是一个端到端架构&#xff0c;直接从任意数量的摄像头数据提取给定图像场景的鸟瞰图表示。将每个图像分别“提升&#xff08;lift&#xff09;”到每个摄像头的视锥&#xff08;frustum&#xff09;&#xff0c;然后将所有视锥“投放&#xff08;splat&a…

Spring相关面试题(四)

49 JavaConfig方式如何启用AOP?如何强制使用cglib&#xff1f; 在JavaConfig类&#xff0c;加上EnableAspectJAutoProxy 如果要强制使用CGLIB动态代理 &#xff0c;加上(proxyTargetClass true) 加上(exposeProxy true) 就是将对象暴露到线程池中。 50 介绍AOP在Spring中…