python一键登录srun校园网(以深圳技术大学为例)

news2024/11/19 18:37:33

全世界最(不)好的目录

  • 一、需求分析
  • 二、实现过程
    • 2.1 分析api
      • 2.1.1 连接到校园网,自动弹出登录认证界面
      • 2.1.2 先输入错误的账号密码,按F12看会获取哪些信息
      • 2.1.3 api
    • 2.2 分析加密
    • 2.3 流程总结
  • 三.模拟登录
    • 3.1 编写配置文件
    • 3.2.功能封装与定时
  • 四.题外话


一、需求分析

指路:https://www.srun.com/cn/list/info?id=44

Srun4K 校园网解决方案,这群人自以为自己的系统搞得很好,可以帮助使用者偷懒的管理网络,但是对于用户端其实每天充斥着断网、卡顿、认证不跳等诸多问题,所以写个客户端便捷的进行断网重连。

二、实现过程

这里本来不想写的,但是某人要求教教他抓包,我就不点名了
由于人在公司,所以截图部分等我想弄的时候再弄吧

2.1 分析api

2.1.1 连接到校园网,自动弹出登录认证界面

http://172.19.0.5/srun_portal_success?ac_id=28&theme=pro&wlanacname=&wlanuserip=10.161.21.150

2.1.2 先输入错误的账号密码,按F12看会获取哪些信息

在这里插入图片描述

2.1.3 api

get_challenge
请求方式为get,地址为
http://172.19.0.5/cgi-bin/get_challenge

请求的数据为

在这里插入图片描述

参数分析
callbackjsonp解决跨域的参数
username校园网账户
ip本机自动获取到的ip
_当前时间戳(32)位

这里是不需要分析的。唯一需要注意的是challenge,因为太过诡异。


srun_portal
请求方式为get,地址为
http://172.19.0.5/cgi-bin/srun_portal
请求数据为
在这里插入图片描述
看到这一大串,可能不太好下手。确实参数有点多。
多观察几次,先找不变的参数,排除掉。

参数分析
callback和第一次的callback意思一样,排除
actionlogin
username账户
ac_id1(意义不详,每次都一样可以排除了)
ip自动获取的ip
n200(和ac_id一样排除)
type1(和ac_id一样排除)
oswindows10
namewindows
double_stack0
_当前时间戳(13位)

一共14个参数,一下子pass11个,还剩下3个参数分别是 password chksum info
接下来开始分析js文件,一共4个
搜索关键字:password
在这里插入图片描述
这个是什么,这个不就是我们请求的参数吗,一下全都出来了,继续搜索对应关键字。
在这里插入图片描述
hmd5就找出来了,是经过md5加密之后的密码,还做过加盐处理
至于token就是之前的challenge

接下来是chksum一样的方法,搜索关键字。
在这里插入图片描述
可以发现是简单的字符串拼接。然后用sha1加密得出chksum。
可是还有个i是什么呢。继续找吧
在这里插入图片描述
都出来了,对象转为字符串之后进行xEncode(天知道是什么加密方式)进行加密,反正也是加盐的加密。也用到了token。之后再进行一次base64加密。i就出来了
i出来了,chksum也出来了。顺序不能错。
处理顺序

参数加密方式
passwordHmac MD5加密
chksumsha1处理
3个参数都需要用到token,至于加密方式更加是坑
只有sha1和md5是可以直接用的。
xencode更加不知道是什么鬼东西,base64是经过改动的。和正常的base64是不一样的。

2.2 分析加密

python版的xencode

import math
def force(msg):
    ret = []
    for w in msg:
        ret.append(ord(w))
    return bytes(ret)
def ordat(msg, idx):
    if len(msg) > idx:
        return ord(msg[idx])
    return 0
def sencode(msg, key):
    l = len(msg)
    pwd = []
    for i in range(0, l, 4):
        pwd.append(
            ordat(msg, i) | ordat(msg, i + 1) << 8 | ordat(msg, i + 2) << 16
            | ordat(msg, i + 3) << 24)
    if key:
        pwd.append(l)
    return pwd
def lencode(msg, key):
    l = len(msg)
    ll = (l - 1) << 2
    if key:
        m = msg[l - 1]
        if m < ll - 3 or m > ll:
            return
        ll = m
    for i in range(0, l):
        msg[i] = chr(msg[i] & 0xff) + chr(msg[i] >> 8 & 0xff) + chr(
            msg[i] >> 16 & 0xff) + chr(msg[i] >> 24 & 0xff)
    if key:
        return "".join(msg)[0:ll]
    return "".join(msg)
def get_xencode(msg, key):
    if msg == "":
        return ""
    pwd = sencode(msg, True)
    pwdk = sencode(key, False)
    if len(pwdk) < 4:
        pwdk = pwdk + [0] * (4 - len(pwdk))
    n = len(pwd) - 1
    z = pwd[n]
    y = pwd[0]
    c = 0x86014019 | 0x183639A0
    m = 0
    e = 0
    p = 0
    q = math.floor(6 + 52 / (n + 1))
    d = 0
    while 0 < q:
        d = d + c & (0x8CE0D9BF | 0x731F2640)
        e = d >> 2 & 3
        p = 0
        while p < n:
            y = pwd[p + 1]
            m = z >> 5 ^ y << 2
            m = m + ((y >> 3 ^ z << 4) ^ (d ^ y))
            m = m + (pwdk[(p & 3) ^ e] ^ z)
            pwd[p] = pwd[p] + m & (0xEFB8D130 | 0x10472ECF)
            z = pwd[p]
            p = p + 1
        y = pwd[0]
        m = z >> 5 ^ y << 2
        m = m + ((y >> 3 ^ z << 4) ^ (d ^ y))
        m = m + (pwdk[(p & 3) ^ e] ^ z)
        pwd[n] = pwd[n] + m & (0xBB390742 | 0x44C6F8BD)
        z = pwd[n]
        q = q - 1
    return lencode(pwd, False)

python版base64

_PADCHAR = "="
_ALPHA = "LVoJPiCN2R8G90yg+hmFHuacZ1OWMnrsSTXkYpUq/3dlbfKwv6xztjI7DeBE45QA"
def _getbyte(s, i):
    x = ord(s[i]);
    if (x > 255):
        print("INVALID_CHARACTER_ERR: DOM Exception 5")
        exit(0)
    return x
def get_base64(s):
    i=0
    b10=0
    x = []
    imax = len(s) - len(s) % 3;
    if len(s) == 0:
        return s
    for i in range(0,imax,3):
        b10 = (_getbyte(s, i) << 16) | (_getbyte(s, i + 1) << 8) | _getbyte(s, i + 2);
        x.append(_ALPHA[(b10 >> 18)]);
        x.append(_ALPHA[((b10 >> 12) & 63)]);
        x.append(_ALPHA[((b10 >> 6) & 63)]);
        x.append(_ALPHA[(b10 & 63)])
    i=imax
    if len(s) - imax ==1:
        b10 = _getbyte(s, i) << 16;
        x.append(_ALPHA[(b10 >> 18)] + _ALPHA[((b10 >> 12) & 63)] + _PADCHAR + _PADCHAR);
    else:
        b10 = (_getbyte(s, i) << 16) | (_getbyte(s, i + 1) << 8);
        x.append(_ALPHA[(b10 >> 18)] + _ALPHA[((b10 >> 12) & 63)] + _ALPHA[((b10 >> 6) & 63)] + _PADCHAR);
    return "".join(x)

md5

import hmac
import hashlib
def get_md5(password,token):
	return hmac.new(token.encode(), password.encode(), hashlib.md5).hexdigest()

sha1

import hmac
import hashlib
def get_md5(password,token):
	return hmac.new(token.encode(), password.encode(), hashlib.md5).hexdigest()

2.3 流程总结

第一次get_challenge是获取token。
中间做了3个信息的处理
最后一步就是登录和认证了

三.模拟登录

完整代码如下:

#coding=utf-8
import ctypes
import hashlib
import json
import math
import random
import socket
import time

import requests


conf = ConfigParser()
conf.read("1.config",encoding='utf-8')
username = conf.get('mysql', 'username')
password = conf.get('mysql', 'password')
init_url="http://172.19.0.5"

def init_getip():
	 """网络获得ip(似乎看起来更靠谱) """
	init_res=requests.get(init_url,headers=header)
	print("初始化获取ip")
	ip=re.search('id="wlanuserip" value="(.*?)"',init_res.text).group(1)
	return ip

def GetLocalIPByPrefix(prefix):
    """ 多网卡情况下,根据前缀获取IP(Windows 下适用) """
    localIP = ''
    for ip in socket.gethostbyname_ex(socket.gethostname())[2]:
        if ip.startswith(prefix):
            localIP = ip
    return localIP
local_ip=GetLocalIPByPrefix('10.')
#local_ip=init_getip()

class MD5(object):

    '''MD5加密//根据js'''
    def a(self, n):
        r = ''
        e = 32 * len(n)
        for i in range(0,e,8):
            r += chr((n[i >> 5] >> i % 32 & 0xffffffff >> i % 32) & 255)
        return r

    def d(self, n):
        r = [0 for _ in range(len(n) >> 2)]
        e = 8 * len(n)
        for i in range(0,e,8):
            if i >> 5 == len(r):
                r.append(0)
            r[i >> 5] |= ctypes.c_int32((255 & ord(n[i // 8])) << i % 32).value
        return r

    def t(self, n, t):
        r = (65535 & n) + (65535 & t)
        a = ctypes.c_int32(n >> 16).value
        b = ctypes.c_int32(t >> 16).value
        c = ctypes.c_int32(r >> 16).value
        d = ctypes.c_int32(a + b + c << 16).value
        return d | 65535 & r

    def r(self, n, t):
        return ctypes.c_int32(n << t).value | (n >> 32 - t & 0xffffffff >> 32 - t)

    def e(self, n, e, o, u, c, f):
        return self.t(self.r(self.t(self.t(e, n), self.t(u, f)), c), o)

    def o(self, n, t, r, o, u, c, f):
        return self.e(t & r | ~t & o, n, t, u, c, f)

    def u(self, n, t, r, o, u, c, f):
        return self.e(t & o | r & ~o, n, t, u, c, f)

    def c(self, n, t, r, o, u, c, f):
        return self.e(t ^ r ^ o, n, t, u, c, f)

    def f(self, n, t, r, o, u, c, f):
        return self.e(r ^ (t | ~o), n, t, u, c, f)

    def i(self, n, r):
        x = 14 + (r + 64 >> 9 << 4) + 1
        n.extend([0 for _ in range(x - len(n))])
        n[-1] = r
        n[r >> 5] |= ctypes.c_int32(128 << r % 32).value
        l = 1732584193
        g = -271733879
        v = -1732584194
        m = 271733878
        for j in range(0,len(n),16):
            if j + 15 >= len(n):
                x = j + 15 - len(n) + 1
                for _ in range(x):
                    n.append(0)
            i = l
            a = g
            d = v
            h = m
            l = self.o(l, g, v, m, n[j], 7, -680876936)
            m = self.o(m, l, g, v, n[j + 1], 12, -389564586)
            v = self.o(v, m, l, g, n[j + 2], 17, 606105819)
            g = self.o(g, v, m, l, n[j + 3], 22, -1044525330)
            l = self.o(l, g, v, m, n[j + 4], 7, -176418897)
            m = self.o(m, l, g, v, n[j + 5], 12, 1200080426)
            v = self.o(v, m, l, g, n[j + 6], 17, -1473231341)
            g = self.o(g, v, m, l, n[j + 7], 22, -45705983)
            l = self.o(l, g, v, m, n[j + 8], 7, 1770035416)
            m = self.o(m, l, g, v, n[j + 9], 12, -1958414417)
            v = self.o(v, m, l, g, n[j + 10], 17, -42063)
            g = self.o(g, v, m, l, n[j + 11], 22, -1990404162)
            l = self.o(l, g, v, m, n[j + 12], 7, 1804603682)
            m = self.o(m, l, g, v, n[j + 13], 12, -40341101)
            v = self.o(v, m, l, g, n[j + 14], 17, -1502002290)
            g = self.o(g, v, m, l, n[j + 15], 22, 1236535329)
            l = self.u(l, g, v, m, n[j + 1], 5, -165796510)
            m = self.u(m, l, g, v, n[j + 6], 9, -1069501632)
            v = self.u(v, m, l, g, n[j + 11], 14, 643717713)
            g = self.u(g, v, m, l, n[j], 20, -373897302)
            l = self.u(l, g, v, m, n[j + 5], 5, -701558691)
            m = self.u(m, l, g, v, n[j + 10], 9, 38016083)
            v = self.u(v, m, l, g, n[j + 15], 14, -660478335)
            g = self.u(g, v, m, l, n[j + 4], 20, -405537848)
            l = self.u(l, g, v, m, n[j + 9], 5, 568446438)
            m = self.u(m, l, g, v, n[j + 14], 9, -1019803690)
            v = self.u(v, m, l, g, n[j + 3], 14, -187363961)
            g = self.u(g, v, m, l, n[j + 8], 20, 1163531501)
            l = self.u(l, g, v, m, n[j + 13], 5, -1444681467)
            m = self.u(m, l, g, v, n[j + 2], 9, -51403784)
            v = self.u(v, m, l, g, n[j + 7], 14, 1735328473)
            g = self.u(g, v, m, l, n[j + 12], 20, -1926607734)
            l = self.c(l, g, v, m, n[j + 5], 4, -378558)
            m = self.c(m, l, g, v, n[j + 8], 11, -2022574463)
            v = self.c(v, m, l, g, n[j + 11], 16, 1839030562)
            g = self.c(g, v, m, l, n[j + 14], 23, -35309556)
            l = self.c(l, g, v, m, n[j + 1], 4, -1530992060)
            m = self.c(m, l, g, v, n[j + 4], 11, 1272893353)
            v = self.c(v, m, l, g, n[j + 7], 16, -155497632)
            g = self.c(g, v, m, l, n[j + 10], 23, -1094730640)
            l = self.c(l, g, v, m, n[j + 13], 4, 681279174)
            m = self.c(m, l, g, v, n[j], 11, -358537222)
            v = self.c(v, m, l, g, n[j + 3], 16, -722521979)
            g = self.c(g, v, m, l, n[j + 6], 23, 76029189)
            l = self.c(l, g, v, m, n[j + 9], 4, -640364487)
            m = self.c(m, l, g, v, n[j + 12], 11, -421815835)
            v = self.c(v, m, l, g, n[j + 15], 16, 530742520)
            g = self.c(g, v, m, l, n[j + 2], 23, -995338651)
            l = self.f(l, g, v, m, n[j], 6, -198630844)
            m = self.f(m, l, g, v, n[j + 7], 10, 1126891415)
            v = self.f(v, m, l, g, n[j + 14], 15, -1416354905)
            g = self.f(g, v, m, l, n[j + 5], 21, -57434055)
            l = self.f(l, g, v, m, n[j + 12], 6, 1700485571)
            m = self.f(m, l, g, v, n[j + 3], 10, -1894986606)
            v = self.f(v, m, l, g, n[j + 10], 15, -1051523)
            g = self.f(g, v, m, l, n[j + 1], 21, -2054922799)
            l = self.f(l, g, v, m, n[j + 8], 6, 1873313359)
            m = self.f(m, l, g, v, n[j + 15], 10, -30611744)
            v = self.f(v, m, l, g, n[j + 6], 15, -1560198380)
            g = self.f(g, v, m, l, n[j + 13], 21, 1309151649)
            l = self.f(l, g, v, m, n[j + 4], 6, -145523070)
            m = self.f(m, l, g, v, n[j + 11], 10, -1120210379)
            v = self.f(v, m, l, g, n[j + 2], 15, 718787259)
            g = self.f(g, v, m, l, n[j + 9], 21, -343485551)
            l = self.t(l, i)
            g = self.t(g, a)
            v = self.t(v, d)
            m = self.t(m, h)
        return [l, g, v, m]

    def l(self, n, t):
        o = self.d(n)
        u = [0 for _ in range(16)]
        c = [0 for _ in range(16)]
        if len(o) > 16:
            o = self.i(o, 8 * len(n))
        for j in range(16):
            u[j] = 909522486 ^ o[j]
            c[j] = 1549556828 ^ o[j]
        u.extend(self.d(t))
        e = self.i(u, 512 + 8 * len(t))
        c.extend(e)
        r = self.a(self.i(c, 640))
        return r

    def s(self, n, t):
        return self.l(n, t)

    def g(self, n):
        d = list('0123456789abcdef')
        e = []
        for c in list(n):
            c = ord(c)
            e.append(d[c >> 4 & 15])
            e.append(d[15 & c])
            r = ''.join(e)
        return r

    def C(self, n, t):
        return self.g(self.s(n, t))

    def __call__(self, password, token):
        return self.C(token, password)
class BASE64:
    #js:atob() base64加密
    def __init__(self):
        self.base64Alpha = 'LVoJPiCN2R8G90yg+hmFHuacZ1OWMnrsSTXkYpUq/3dlbfKwv6xztjI7DeBE45QA'

    def encode(self, s):
        r = []
        x = len(s) % 3
        if x:
            s = s + '\0'*(3 - x)
        for i in range(0,len(s),3):
            d = s[i:i+3]
            a = ord(d[0]) << 16 | ord(d[1]) << 8 | ord(d[2])
            r.append(self.base64Alpha[a>>18])
            r.append(self.base64Alpha[a>>12 & 63])
            r.append(self.base64Alpha[a>>6 & 63])
            r.append(self.base64Alpha[a & 63])
        if x == 1:
            r[-1] = '='
            r[-2] = '='
        if x == 2:
            r[-1] = '='
        return ''.join(r)
def getTime():
    #取时间 等同于js里面的 Date.toValue()
    t = time.time()
    return int(round(t * 1000))
callback = 'jQuery{0}_{1}'.format(random.getrandbits(100), getTime())
def get_challenge():
    #登录认证第一步
    url = 'http://172.19.0.5/cgi-bin/get_challenge'
    headers = {
        'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36 Edg/95.0.1020.30'
    }
    #callback = 'jQuery{0}_{1}'.format(random.getrandbits(100), getTime())
    params = {'callback':callback,
              'username':username,
              'ip':local_ip,
              '_':getTime()}
    r = requests.get(url, params=params, headers=headers)
    #print(r.url)
    print(r.text)
    data = r.text[len(callback)+1:-1]
    token = json.loads(data)['challenge']
    return token
def statusTest():
    #ping 百度来测试网络是否连通
    import subprocess
    ret = subprocess.run("ping baidu.com -n 1", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    s1 = str(ret.stdout, encoding='gbk')
    return True if "0% 丢失" in s1 else False
def encode_userinfo(userinfo, token):
    #对用户信息进行SRBX1
    userinfo = json.dumps(userinfo).replace(' ','')
    if len(userinfo) == 0:
        return ''
    sc = len(userinfo)
    if sc % 4:
        userinfo += '\0' * (4-(sc%4))
    sv = []
    for i in range(0, sc, 4):
        while i >> 2 >= len(sv):
            sv.append(0)
        sv[i >> 2] = ord(userinfo[i]) | ctypes.c_int32(ord(userinfo[i+1]) << 8).value | \
                     ctypes.c_int32(ord(userinfo[i+2]) << 16).value | ctypes.c_int32(ord(userinfo[i+3]) << 24).value
    sv.append(sc)
    v = sv[:]
    sc = len(token)
    sv = []
    for i in range(0, sc, 4):
        while i >> 2 >= len(sv):
            sv.append(0)
        sv[i >> 2] = ord(token[i]) | ctypes.c_int32(ord(token[i+1]) << 8).value | \
                     ctypes.c_int32(ord(token[i+2]) << 16).value | ctypes.c_int32(ord(token[i+3]) << 24).value
    k = sv[:]
    while len(k) < 4:
        k.append(0)
    n = len(v) - 1
    z = v[n]
    y = v[0]
    c = ctypes.c_int32(0x86014019 | 0x183639A0).value
    q = math.floor(6 + 52 / (n + 1))
    d = 0
    m = None
    e = None
    while q > 0:
        d = d + c & (0x8CE0D9BF | 0x731F2640)
        d = ctypes.c_int32(d).value
        e = (d >> 2 & 0xFFFFFFFF >> 2) & 3
        for p in range(n):
            y = v[p + 1]
            m = (z >> 5 & 0xFFFFFFFF >> 5) ^ ctypes.c_int32(y << 2).value
            m += (y >> 3 & 0xFFFFFFFF >> 3) ^ ctypes.c_int32(z << 4).value ^ (d ^ y)
            m += k[p & 3 ^ e] ^ z
            v[p] = ctypes.c_int32(v[p] + m & (0xEFB8D130 | 0x10472ECF)).value
            z = v[p]
        y = v[0]
        m = (z >> 5 & 0xFFFFFFFF >> 5) ^ ctypes.c_int32(y << 2).value
        m += (y >> 3 & 0xFFFFFFFF >> 3) ^ ctypes.c_int32(z << 4).value ^ (d ^ y)
        m += k[(p + 1) & 3 ^ e] ^ z
        v[n] =ctypes.c_int32(v[n] + m & (0xBB390742 | 0x44C6F8BD)).value
        z = v[n]
        q -= 1
    lv = v[:]
    ld = len(lv)
    lc = ctypes.c_int32(ld - 1 << 2).value
    for i in range(ld):
        lv[i] = ''.join([chr(lv[i] & 0xff), chr((lv[i] >> 8 & 0xFFFFFFFF >> 8) & 0xff),
                        chr((lv[i] >> 16 & 0xFFFFFFFF >> 16) & 0xff),
                        chr((lv[i] >> 24 & 0xFFFFFFFF >> 24) & 0xff)])
    l = ''.join(lv)
    base64 = BASE64()
    return r'{SRBX1}' + base64.encode(l)

def srun_portal(username,password):
    #登录认证第二部
    url = 'http://172.19.0.5/cgi-bin/srun_portal'
    headers = {
        'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36 Edg/106.0.1370.47'
    }
    #callback = 'jQuery{0}_{1}'.format(random.getrandbits(100),getTime())
    md5 = MD5()
    token= get_challenge()
    hmd5 = md5(password, token)
    userinfo = {'username':username,
                'password':password,
                'ip':local_ip,
                'acid':'28',
                'enc_ver': 'srun_bx1'
                }
    info = encode_userinfo(userinfo, token)
    chkstr = token+username+token+hmd5+token+'28'+token+local_ip+token+'200'+token+'1'+token+info
    sha1 = hashlib.sha1()
    sha1.update(chkstr.encode())
    chksum = sha1.hexdigest()
    params = {'callback':callback,
              'action':'login',
              'username':username,
              'password':r'{MD5}' + hmd5,
              'os':'Windows10',
              'name':'Windows',
              'double_stack':0,
              'chksum':chksum,
              'info':info,
              'ac_id':28,
              'ip':local_ip,
              'n':200,
              'type':1,
              '_':getTime()}
    r = requests.get(url, params=params, headers=headers)
    print(r.text)
    if 'Login is successful' in r.text:
        print('登录认证成功!')
    elif 'ip_already_online' in r.text:
        print("您已在线!")
    elif statusTest()==True:
        print("您虽然不在线但是有网")
    else:
        print('登陆失败,请检查acid或者密码是否正确')
def main():
    if local_ip == '':
        print('本机IP获取失败,请检查网络连接')

    username=input("用户名")
    password=input("密码")
    print('登录用户名:{}'.format(username))
    print('本机ipv4地址:{}'.format(local_ip))
    srun_portal(username,password)

if __name__ == '__main__':
    temp=local_ip
    while True:
        main()
        time.sleep(3600)

3.1 编写配置文件

配置文件如下:
1.config

[mysql]
username=
password=

3.2.功能封装与定时

完成上面的步骤之后我们就可以开始对登陆代码进行封装了,然后定时一小时重新登陆一次即可。

四.题外话

在这里插入图片描述
校园网安全认证和提高信息技术水平有个毛关系?要么是为了限制设备数圈钱(说这的那的,网费和居民区一样贵服务还差),要么就是…
总之没见过这么对付的商业计划书。

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

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

相关文章

【微软Bing王炸更新】无需等待,人人可用,答案图文并茂,太牛了

&#x1f680; AI破局先行者 &#x1f680; &#x1f332; AI工具、AI绘图、AI专栏 &#x1f340; &#x1f332; 如果你想学到最前沿、最火爆的技术&#xff0c;赶快加入吧✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;CSDN-Java领域优质创作者&#x1f3c6;&am…

opencv实践项目-图像拼接

目录 1.简介2. 步骤2.1 特征检测与提取2.2 关键点检测2.3 关键点和描述符2.4 特征匹配2.5 比率测试2.6 估计单应性 3. 完整代码 1.简介 图像拼接是计算机视觉中最成功的应用之一。如今&#xff0c;很难找到不包含此功能的手机或图像处理API。在本 文中&#xff0c;我们将讨论如…

虹科分享 | 专为创意专业人士设计的Thunderbolt适配器

一、方案介绍 虹科HK-ATTO ThunderLink雷电™ 适配器可以适用于任何地方。 1.小。 2.便携式。 3.强大。 我们的10GBE Thunderbolt适配器的性能至少比内置或附加NIC&#xff08;包括Mac&#xff09;高20% , ATTO 360只需点击一个按钮即可优化以太网SAN&#xff0c;并可与Thunder…

xxl-job 使用示例

目录 介绍 下载源码地址 文档网站 源码导入就是这样目录 数据库建表sql 就这么几个表出来了 修改xxl-job-admin项目下的application.properties文件 完事启动就行了 页面 页面访问地址 账号密码 增加自己的定时任务 介绍 这篇写的是接入使用xxl-job 的一个简单流程…

win系统使用macOS系统

最近 win 系统和 ubuntu 系统用的久了&#xff0c;想用一下 MacOS 系统&#xff0c;于是去网上查了相关资料&#xff0c;发现用一款叫 NEXUS 的软件可以实现在 windows 系统体验效果&#xff0c;现把教程记录下来&#xff0c;供大家使用。 目录 一、下载NEXUS 二、 安装NEXU…

IMX6ULL裸机篇之串口实验说明一

一. 串口 本章我们就来学习如何驱动 I.MX6U 上的串口&#xff0c;并使用串口和电脑进行通信。 串行接口指的是数据一个一个的顺序传输&#xff0c;通信线路简单。 UART 作为串口的一种&#xff0c;其工作原理也是将数据一位一位的进行传输&#xff0c;发送和接收各用一 条…

win11本地安全机构保护已关闭怎么办?如何修复windows11本地安全机构保护已关闭?

win11本地安全机构保护已关闭怎么办&#xff1f; 如何修复windows11本地安全机构保护已关闭&#xff1f; 近日有windows11系统用户反映说遇到了这样一个问题&#xff1a;启动电脑后&#xff0c;发现windows右下角的安全中心图标上会显示一个黄色叹号&#xff0c;打开windows安…

操作系统笔记--进程与线程

1--进程 1-1--进程的定义 进程表示一个具有一定独立功能的程序在一个数据集合上的一次动态执行过程&#xff1b; 1-2--进程的组成 一个进程由以下部分组成&#xff1a;① 程序的代码&#xff1b; ② 程序处理的数据&#xff1b;③ 程序计数器中的值&#xff0c;其指示下一条将…

PHP流行框架的报错页面,你见过那些?

在PHP开发过程中&#xff0c;使用框架能够帮助我们更快速、高效地完成项目开发。但是&#xff0c;即使使用了框架&#xff0c;我们还是难免会遇到各种报错。而当我们在开发阶段或调试过程中遇到报错时&#xff0c;框架提供的错误页面可以给我们带来很大的帮助。PHP常用的流行框…

网易一面:如何设计线程池?请手写一个简单线程池?

说在前面 在40岁老架构师 尼恩的读者社区(50)中&#xff0c;最近有小伙伴拿到了一线互联网企业如极兔、有赞、希音、百度、网易的面试资格&#xff0c;遇到了几个很重要的面试题&#xff1a; 如何设计线程池&#xff1f; 与之类似的、其他小伙伴遇到过的问题还有&#xff1a; …

Reinhart FoodService的EDI需求详解

Reinhart FoodService是一家成立于1972年的美国食品服务公司&#xff0c;隶属于上市公司Performance Food Group。Reinhart FoodService为餐馆、酒店、医院、学校等各类机构提供广泛的食品选择和相关服务&#xff0c;产品包括新鲜的肉类、禽类、海鲜、奶制品、烘焙用品、蔬菜和…

迪赛智慧数——柱状图(象形动态图):不同性别消费者点外卖频率

效果图 我国超4亿人叫外卖&#xff0c;你多久点一次外卖? 据数据显示&#xff0c;30.7%男性消费者每周点3-4次外卖&#xff0c;34.3%的女性每周点3-4次&#xff0c;明显女性比男性点外卖频率多。而每周点1-2次外卖中均超过80%。 数据源&#xff1a;静态数据 { "column&…

MIT开源协议,多端适用的租房小程序,带完整的管理员后台

一、开源项目简介 多端适用的租房小程序&#xff0c;带管理员后台。是一个完整的项目&#xff0c;可以直接使用。 二、开源协议 使用MIT开源协议 三、界面展示 部分截图 1. 前台截图 2. 后台截图 四、功能概述 1、使用Uniapp开发的前台&#xff0c;基于 Vue.js 开发所有…

2 种方式在流水线中集成 DAST,动态保护应用程序安全

&#x1f4a1; 如何在流水线中集成与应用 DAST &#xff1f; 近日&#xff0c;在「DevSecOps软件安全开发实践」课程上&#xff0c;极狐(GitLab) 前端工程师钱堃、极狐(GitLab) 高级后端工程师张林杰&#xff0c;展开了关于 DAST 的概念、必要性、优缺点的内容分享&#xff0c;…

如何完美实现数据可视化?

为什么要可视化数据? 在工作中&#xff0c;无论你在哪个场景&#xff0c;你都会接触到数据&#xff0c;需要表达出来。数据可视化的作用是通过结合图表和数据来更好地传达业务信息。目前&#xff0c;大多数公司正在逐步从传统的流程管理过渡到基于数据的管理。数据可视化可以…

明明花钱上了ERP,为什么还要我装个MES系统

目前&#xff0c; ERP系统依旧是很多制造企业的选择。据统计&#xff0c;ERP系统的应用已经达到70&#xff05;以上&#xff0c;但是在车间的应用&#xff0c; MES系统的应用比例并不高。那么&#xff0c;为什么现在很多企业又都选择再上个MES呢&#xff1f; MES系统是一个面向…

高性能HMI 走向扁平化

个人计算机作为图形用户界面&#xff08;GUI&#xff09;在自动化中已经使用了30多年。在那段时间里&#xff0c;从技术、术语、功能到用于创建接口的标准和指南&#xff0c;发生了许多变化。 PC 技术的飞速发展&#xff0c;特别是图形显示&#xff0c;用户界面的技术发展导致了…

分享8款开源的自动化测试框架

在如今开源的时代&#xff0c;我们就不要再闭门造车了&#xff0c;热烈的拥抱开源吧&#xff01;本文针对性能测试、Web UI 测试、API 测试、数据库测试、接口测试、单元测试等方面&#xff0c;为大家整理了github或码云上优秀的自动化测试开源项目&#xff0c;希望能给大家带来…

PyQt5零基础入门(二)——主窗口的显示与退出

系列文章目录 PyQt5与QtDesigner的安装及测试 创建主窗口和状态栏 系列文章目录PyQt5与QtDesigner的安装及测试 前言主窗口代码运行结果解释 窗口居中代码解释 退出窗口代码运行结果解释 前言 本文主要介绍了如何使用PyQt5创建第一个主窗口&#xff0c;并向其中添加状态栏和消…

Contest3137 - 2022-2023-2 ACM集训队每月程序设计竞赛(1)五月月赛

A 1! 5! 46 169 有一种数字&#xff0c;我们称它为 纯真数。 它等于自身每一个数位的阶乘之和。请你求出不超过n的所有 纯真数。(注&#xff1a;纯真数不含有前导0&#xff09;数据范围1e18 纯真数只有四个&#xff0c;注意0!1 1,2,145,40585 int n;cin>>n;int res[]{…