【JS逆向课件:第十三课:异步爬虫】

回顾

  • 并行和并发

    • 表示程序/计算机具有处理多个任务的能力
      • 并行表示可以同时处理多个任务(几个多核CPU)
      • 并发无法同时处理多个任务,但是可以基于时间片轮转法在多任务间快速切换的执行任务。
  • 同步和异步

    • 在基于并行或者并发处理任务的时候,任务中如果出现阻塞操作,就可以选择使用同步或者异步的方式进行处理阻塞操作。
      • 同步处理:让CPU等待阻塞操作结束后,在继续执行处理阻塞后面的其他操作。
      • 异步处理:遇到阻塞操作当前任务会交出CPU的使用权,让CPU可以继续处理其他任务。
        • 因此,在异步应用的过程中,如果一个任务出现了阻塞操作,可以将阻塞操作单独封装成一个单独的任务。
  • 进程和线程

    • 是用来实现异步的两种技术手段
    • 在异步应用的过程中,如果一个任务出现了阻塞操作,可以将阻塞操作单独封装成一个单独的任务,这个任务就是进程或者线程。

协程(重要!)

  • 我们知道,无论是多进程还是多线程,在遇到IO阻塞时都会被操作系统强行剥夺走CPU的执行权限(使得cup执行其他操作,其他操作可能是我们程序的其他部分,也可能是其他的应用程序),我们自己程序的执行效率因此就降低了下来。

  • 解决这一问题的关键在于:

    • 我们自己从自己的应用程序级别检测到IO阻塞,然后使得cpu切换到我们自己程序的其他部分/任务执行(这里的任务指的是当前我们自己程序表示的进程或线程中的某一组操作/子程序),这样可以把我们程序的IO阻塞降到最低,我们的程序处于就绪态就会增多,以此来迷惑操作系统,操作系统便以为我们的程序是IO阻塞比较少的程序,从而会尽可能多的分配CPU给我们,这样也就达到了提升程序执行效率的目的。
      • 通俗理解:
        • 一个线程/进程可以表示一组指定行为的操作,这个操作可以由多个执行步骤组成,这些执行步骤有的是阻塞操作有的非阻塞操作,那么,当cpu执行当前进程/线程的时候遇到了阻塞的执行步骤的时候,如果不对其处理,则包含当前执行步骤的进程/线程就会被挂起进入到阻塞状态,且交出cpu的使用权(cpu就被别人抢走了)。那么如果遇到阻塞的执行步骤,我们的程序可以检测出它是阻塞的,且可以将cpu切换到我们自己程序其他非阻塞的执行步骤时,则包含这些执行步骤的进程/线程就不会进入到阻塞状态,从而减少进程/线程的阻塞状态,增加就绪状态(牢牢抢占cup)极大幅度提升程序执行的效率。
        • 因此,有了协程后,在单进程或者单线程的模式下,就可以大幅度提升程序的运行效率了!
  • 在python3.5之后新增了asyncio模块,可以帮我们检测IO(只能是网络IO【HTTP连接就是网络IO操作】),实现应用程序级别的切换(异步IO)。

  • 接下来让我们来了解下协程的实现,从 Python 3.4 开始,Python 中加入了协程的概念,但这个版本的协程还是以生成器对象为基础的,在 Python 3.5 则增加了 asyncio,使得协程的实现更加方便。首先我们需要了解下面几个概念:

    • 特殊函数:

      • 在函数定义前添加一个async关键字,则该函数就变为了一个特殊的函数!
      • 特殊函数的特殊之处是什么?
        • 1.特殊函数被调用后,函数内部的程序语句(函数体)没有被立即执行
        • 2.特殊函数被调用后,会返回一个协程对象
    • 协程:

      • 协程对象,特殊函数调用后就可以返回/创建了一个协程对象。
      • 协程对象 == 特殊的函数 == 一组指定形式的操作
        • 协程对象 == 一组指定形式的操作
    • 任务:

      • 任务对象就是一个高级的协程对象。高级之处,后面讲,不着急!
      • 任务对象 == 协程对象 == 一组指定形式的操作
        • 任务对象 == 一组指定形式的操作
    • 事件循环:

      • 事件循环对象(Event Loop),可以将其当做是一个容器,该容器是用来装载任务对象的。所以说,让创建好了一个或多个任务对象后,下一步就需要将任务对象全部装载在事件循环对象中。
      • 思考:为什么需要将任务对象装载在事件循环对象?
        • 当将任务对象装载在事件循环中后,启动事件循环对象,则其内部装载的任务对象对应的相关操作就会被立即执行。
    • import asyncio
      import time
      #特殊的函数
      async def get_request(url):print('正在请求的网址是:',url)time.sleep(2)print('请求网址结束!')return 123
      #创建了一个协程对象
      c = get_request('www.1.com')
      #创建任务对象
      task = asyncio.ensure_future(c)
      #创建事件循环对象
      loop = asyncio.get_event_loop()
      #将任务对象装载在loop对象中且启动事件循环对象
      loop.run_until_complete(task)
      
      • 任务对象对比协程对象的高级之处重点在于:

        • 可以给任务对象绑定一个回调函数!

        • 回调函数有什么作用?

          • 回调函数就是回头调用的函数,因此要这么理解,当任务对象被执行结束后,会立即调用给任务对象绑定的这个回调函数!
        • import asyncio
          import time
          #特殊的函数
          async def get_request(url):print('正在请求的网址是:',url)time.sleep(2)print('请求网址结束!')return 123
          #回调函数的封装:必须有一个参数
          def t_callback(t):#参数t就是任务对象# print('回调函数的参数t是:',t)# print('我是任务对象的回调函数!')data = t.result()#result()函数就可以返回特殊函数内部的返回值print('我是任务对象的回调函数!,获取到特殊函数的返回值为:',data)
          #创建协程对象
          c = get_request('www.1.com')
          #创建任务对象
          task = asyncio.ensure_future(c)
          #给任务对象绑定回调函数:add_done_callback的参数就是回调函数的名字
          task.add_done_callback(t_callback)#创建事件循环对象
          loop = asyncio.get_event_loop()
          loop.run_until_complete(task)
          
        • 多任务的协程

          • import asyncio
            import time
            start = time.time()
            urls = ['www.1.com','www.2.com','www.3.com'
            ]
            async def get_request(url):print('正在请求:',url)time.sleep(2)print('请求结束:',url)
            #有了三个任务对象和一个事件循环对象
            if __name__ == '__main__':tasks = []for url in urls:c = get_request(url)task = asyncio.ensure_future(c)tasks.append(task)#将三个任务对象,添加到一个事件循环对象中loop = asyncio.get_event_loop()loop.run_until_complete(asyncio.wait(tasks))print('总耗时:',time.time()-start)
            • 出现两个问题:
              • 1.没有实现异步效果
              • 2.wait()是什么意思?
          • wait()函数:

            • 给任务列表中的每一个任务对象赋予一个可被挂起的权限!当cpu执行的任务对象遇到阻塞操作的时候,当前任务对象就会被挂起,则cup就可以执行其他任务对象,提高整体程序运行的效率!
            • 挂起任务对象:让当前正在被执行的任务对象交出cpu的使用权,cup就可以被其他任务组抢占和使用,从而可以执行其他任务组。
            • 注意:特殊函数内部,不可以出现不支持异步模块的代码,否则会中断整个异步效果!
          • await关键字:挂起发生阻塞操作的任务对象。在任务对象表示的操作中,凡是阻塞操作的前面都必须加上await关键字进行修饰!

          • 完整的实现了,多任务的异步协程操作

          • import asyncio
            import time
            start = time.time()
            urls = ['www.1.com','www.2.com','www.3.com'
            ]
            async def get_request(url):print('正在请求:',url)# time.sleep(2) #time模块不支持异步await asyncio.sleep(2)print('请求结束:',url)
            #有了三个任务对象和一个事件循环对象
            if __name__ == '__main__':tasks = []for url in urls:c = get_request(url)task = asyncio.ensure_future(c)tasks.append(task)#将三个任务对象,添加到一个事件循环对象中loop = asyncio.get_event_loop()loop.run_until_complete(asyncio.wait(tasks))print('总耗时:',time.time()-start)
        • 真正的将多任务的异步协程作用在爬虫中

          • 需求:爬取自己服务器中的页面数据,并将其进行数据解析操作

          • aiohttp:是一个基于网络请求的模块,功能和requests相似,但是,requests是不支持异步的,而aiohttp是支持异步的模块。

            • 环境安装:pip install aiohttp

            • 具体用法:

              • 1.先写大致架构

                •     with aiohttp.ClientSession() as sess:#基于请求对象发起请求#此处的get是发起get请求,常用参数:url,headers,params,proxy#post方法发起post请求,常用参数:url,headers,data,proxy#发现处理代理的参数和requests不一样(注意),此处处理代理使用proxy='http://ip:port'with sess.get(url=url) as response:page_text = response.text()#text():获取字符串形式的响应数据#read():获取二进制形式的响应数据return page_text
                  
                • 2.在第一步的基础上补充细节

                  • 在每一个with前加上async关键字

                  • 在阻塞操作前加上await关键字

                  • 完整代码:

                     async def get_request(url):#requests是不支持异步的模块# response = await requests.get(url=url)# page_text = response.text#创建请求对象(sess)async with aiohttp.ClientSession() as sess:#基于请求对象发起请求#此处的get是发起get请求,常用参数:url,headers,params,proxy#post方法发起post请求,常用参数:url,headers,data,proxy#发现处理代理的参数和requests不一样(注意),此处处理代理使用proxy='http://ip:port'async with await sess.get(url=url) as response:page_text = await response.text()#text():获取字符串形式的响应数据#read():获取二进制形式的响应数据return page_text
                    
        • 多任务异步爬虫的完整代码实现:

        • import requests
          import asyncio
          import time
          from lxml import etree
          import aiohttp
          start = time.time()
          urls = ['http://127.0.0.1:5000/bobo','http://127.0.0.1:5000/jay','http://127.0.0.1:5000/tom'
          ]
          #该任务是用来对指定url发起请求,获取响应数据
          async def get_request(url):#requests是不支持异步的模块# response = await requests.get(url=url)# page_text = response.text#创建请求对象(sess)async with aiohttp.ClientSession() as sess:#基于请求对象发起请求#此处的get是发起get请求,常用参数:url,headers,params,proxy#post方法发起post请求,常用参数:url,headers,data,proxy#发现处理代理的参数和requests不一样(注意),此处处理代理使用proxy='http://ip:port'async with await sess.get(url=url) as response:page_text = await response.text()#text():获取字符串形式的响应数据#read():获取二进制形式的响应数据return page_text
          def parse(t):#回调函数专门用于数据解析#获取任务对象请求到的页面源码数据page_text = t.result()tree = etree.HTML(page_text)a = tree.xpath('//a[@id="feng"]/@href')[0]print(a)tasks = []
          for url in urls:c = get_request(url)task = asyncio.ensure_future(c)task.add_done_callback(parse)tasks.append(task)
          loop = asyncio.get_event_loop()
          loop.run_until_complete(asyncio.wait(tasks))print('总耗时:',time.time()-start)
          

异步爬虫具体应用

注意:通常,异步操作主要作用在耗时环节。

同步操作

url:https://www.pkdoutu.com/photo/list/?page=1

import requests
from lxml import etree
import os
dirName = 'imgLibs'
if not os.path.exists(dirName):os.mkdir(dirName)
headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36"
}
for page in range(1,2):url = 'https://www.pkdoutu.com/photo/list/?page=%d'%pagepage_text = requests.get(url,headers=headers).texttree = etree.HTML(page_text)a_alist = tree.xpath('//*[@id="pic-detail"]/div/div[2]/div[2]/ul/li/div/div/a')for a in a_alist:#图片是滑动滚轮后单独加载出来的(图片懒加载)img_src = a.xpath('./img/@data-original')[0]img_title = img_src.split('/')[-1]img_path = dirName+'/'+img_titleimg_data = requests.get(img_src,headers=headers).contentwith open(img_path,'wb') as fp:fp.write(img_data)print(img_title,':爬取保存成功!')
多线程爬取斗图

url:https://www.pkdoutu.com/photo/list/?page=1

import requests
from lxml import etree
import os
from threading import ThreaddirName = 'imgLibs'
if not os.path.exists(dirName):os.mkdir(dirName)headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36"
}# 爬取多页的图片链接,将其存储起来,然后准备后面的异步图片爬取
def get_img_msg():img_msg = [] #存储图片相关信息for page in range(1,2):url = 'https://www.pkdoutu.com/photo/list/?page=%d'%pagepage_text = requests.get(url,headers=headers).texttree = etree.HTML(page_text)a_alist = tree.xpath('//*[@id="pic-detail"]/div/div[2]/div[2]/ul/li/div/div/a')for a in a_alist:#图片是滑动滚轮后单独加载出来的(图片懒加载)img_src = a.xpath('./img/@data-original')[0]img_title = img_src.split('/')[-1]dic = {}dic['img_url'] = img_srcdic['img_title'] = img_titleimg_msg.append(dic)return img_msgdef get_request(dic):img_title = dic['img_title']img_src = dic['img_url']img_path = dirName + '/' + img_titleimg_data = requests.get(img_src, headers=headers).contentwith open(img_path, 'wb') as fp:fp.write(img_data)print(img_title, ':爬取保存成功!')if __name__ == '__main__':img_msg = get_img_msg()for dic in img_msg:thread = Thread(target=get_request, args=(dic,))thread.start()
协程爬取斗图

url:https://www.pkdoutu.com/photo/list/?page=1

import requests
from lxml import etree
import os
import aiohttp
import asynciodirName = 'imgLibs'
if not os.path.exists(dirName):os.mkdir(dirName)headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36"
}# 爬取多页的图片链接,将其存储起来,然后准备后面的异步图片爬取
def get_img_msg():img_msg = [] #存储图片相关信息for page in range(1,2):url = 'https://www.pkdoutu.com/photo/list/?page=%d'%pagepage_text = requests.get(url,headers=headers).texttree = etree.HTML(page_text)a_alist = tree.xpath('//*[@id="pic-detail"]/div/div[2]/div[2]/ul/li/div/div/a')for a in a_alist:#图片是滑动滚轮后单独加载出来的(图片懒加载)img_src = a.xpath('./img/@data-original')[0]img_title = img_src.split('/')[-1]dic = {}dic['img_url'] = img_srcdic['img_title'] = img_titleimg_msg.append(dic)return img_msgasync def get_request(dic):async with aiohttp.ClientSession() as sess:async with await sess.get(url=dic['img_url']) as response:img_data = await response.read()dic['img_data'] = img_datareturn dic#任务对象回调函数:用来进行图片的持久化存储
def saveImg(task):dic = task.result()img_path = dirName+'/'+dic['img_title']with open(img_path, 'wb') as fp:fp.write(dic['img_data'])print(dic['img_title'], ':爬取保存成功!')if __name__ == '__main__':img_msg = get_img_msg()tasks = []for dic in img_msg:c = get_request(dic)task = asyncio.ensure_future(c)task.add_done_callback(saveImg)tasks.append(task)loop = asyncio.get_event_loop()loop.run_until_complete(asyncio.wait(tasks))

M3U8流视频数据爬虫

HLS技术介绍

现在大部分视频客户端都采用HTTP Live Streaming(HLS,Apple为了提高流播效率开发的技术),而不是直接播放MP4等视频文件。HLS技术的特点是将流媒体切分为若干【TS片段】(比如几秒一段),然后通过一个【M3U8列表文件】将这些TS片段批量下载供客户端播放器实现实时流式播放。因此,在爬取HLS的流媒体文件的思路一般是先【下载M3U8文件】并分析其中内容,然后在批量下载文件中定义的【TS片段】,最后将其【组合】成mp4文件或者直接保存TS片段。

M3U8文件详解

如果想要爬取HLS技术下的资源数据,首先要对M3U8的数据结构和字段定义非常了解。M3U8是一个扩展文件格式,由M3U扩展而来。那么什么事M3U呢?

M3U文件

M3U这种文件格式,本质上说不是音频视频文件,它是音频视频文件的列表文件,是纯文本文件。

M3U这种文件被获取后,播放软件并不是播放它,而是根据它的记录找到媒体的网络地址进行在线播放。也就是说,M3U格式的文件只是存储多媒体播放列表,并提供了一个指向其他位置的音频视频文件的索引,播放的是那些被指向的文件。

为了能够更好的理解M3U的概念,我们先简单做一个M3U文件(myTest.m3u)。在电脑中随便找几个MP3,MP4文件依次输入这些文件的路径,myTest.m3u文件内容如下

E:\Users\m3u8\刘德华 - 无间道.mp4
E:\Users\m3u8\那英 - 默.mp3
E:\Users\m3u8\周杰伦 - 不能说的秘密.mp4
E:\Users\m3u8\花粥 - 二十岁的某一天.mp3
E:\Users\m3u8\周深 - 大鱼.mp4
M3U8文件

M3U8也是一种M3U的扩展格式(高级的M3U,所以也属于M3U)。下面我们将了解一下M3U8中定义的几个非常重要的关键字:

#EXTM3U:每个M3U文件第一行必须是这个tag标识。(简单了解)#EXT-X-VERSION:版本,此属性可用可不用。(简单了解)#EXT-X-TARGETDURATION:目标持续时间,是用来定义每个TS的【最大】duration(持续时间)。(简单了解)#EXT-X-ALLOW-CACHE是否允许允许高速缓存。(简单了解)#EXT-X-MEDIA-SEQUENCE定义当前M3U8文件中第一个文件的序列号,每个ts文件在M3U8文件中都有固定唯一的序列号。(简单了解)#EXT-X-DISCONTINUITY:播放器重新初始化(简单了解)#EXTINF:指定每个媒体段(ts文件)的持续时间,这个仅对其后面的TS链接有效,每两个媒体段(ts文件)间被这个tag分隔开。(简单了解)#EXT-X-ENDLIST表明M3U8文件的结束。(简单了解)

**M3U8示例:**大家会看到在该文件中有大量的ts文件的链接地址,这个就是我们之前描述的真正的视频文件。其中任何一个ts文件都是一小段视频,可以单独播放。我们做视频爬虫的目标就是把这些ts文件都爬取下来。

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:6
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:3.127,
/20230512/RzGw5hDB/1500kb/hls/YZefAiEF.ts
#EXTINF:3.127,
/20230512/RzGw5hDB/1500kb/hls/FsliUCL6.ts
#EXTINF:3.127,
/20230512/RzGw5hDB/1500kb/hls/DD7c47bz.ts
#EXT-X-ENDLIST
实战
需求:
  • https://www.99meijutt.com/
具体操作

打开开发者工具,定位到Sources选项卡。在“Sources”选项卡(顶端)中,点击“XHR/fetch Breakpoints”的加号,在编辑框中输入“m3u8”,本操作的意思是:当网页中有任何URL中包含m3u8字段的网络访问就暂停执行。

完成以上操作后重新刷新页面,此时Chrome开发者工具就会暂停在访问M3U8的代码位置。暂停后,我们可以点击左下方的{}图标提高暂停部分代码的可读性。

然后点击”单步“执行按钮,单步执行js代码,执行几部后,会看到一级m3u8的文件地址使用requests进行请求发送,获取一级m3u8文件内容。

在这里插入图片描述

  • 同步操作代码
import requests
from urllib.parse import urljoin
import re
import os
# 需要安装. pip install pycryptodome
from Crypto.Cipher import AES
dirName = 'tsLib'
if not os.path.exists(dirName):os.mkdir(dirName)headers  = {'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36'
}
#一级m3u8地址
m1_url = "https://c2.monidai.com/20230415/7Z6l3a9h/index.m3u8"
m1_page_text = requests.get(url=m1_url,headers=headers).text
#从一级m3u8文件中解析出二级m3u8地址
m1_page_text = m1_page_text.strip()#取出收尾的回车
#二级m3u8地址
m2_url = ''
for line in m1_page_text.split('\n'):if not line.startswith('#'):m2_url = line#补充m2_url:缺少域名m2_url = 'https://h0.rzisytn.cn/'+m2_url#至此就获取到了完整的二级文件地址
#请求二级文件地址内容
m2_page_text = requests.get(url=m2_url,headers=headers).text
m2_page_text = m2_page_text.strip()#解析出每一个ts切片的地址
ts_url_list = []
for line in m2_page_text.split('\n'):if not line.startswith('#'):ts_url = line#不同ts下载地址ts_url = 'https://h0.rzisytn.cn'+ts_urlts_url_list.append(ts_url)#请求到每一个ts切片的数据
for url in ts_url_list:#获取ts片段的数据ts_data = requests.get(url=url,headers=headers).contentts_name = url.split('/')[-1]ts_path = dirName+'/'+ts_namewith open(ts_path,'wb') as fp:#需要将解密后的数据写入文件进行保存fp.write(ts_data)print(ts_name,'下载保存成功!')# ts文件的合并,最好网上找专业的工具进行合并,自己手动合并会经常出问题
  • 异步操作代码

练习
  • 注意:

    • m3u8文件地址需要自己尝试不同的拼接方式探究真正的地址是什么
    • 如果不知道ts的下载地址,可以在浏览器抓包工具中查看ts数据包的url地址,找寻ts完整地址的规律。
  • 网站:https://www.meijuw.com/

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

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

相关文章

链式法则和自动求导

向量链式法则 说明: 1.第一个式子, y是标量,u是标量,x是n维向量 2.第二个式子,y是标量,u是k维向量,x是n维向量,所以y对u求导是k维的行向量,u对x求导是k行n列的矩阵&…

学术研讨 | 区块链治理与应用创新研讨会顺利召开

学术研讨 近日,国家区块链技术创新中心组织,长安链开源社区支持的“区块链治理与应用创新研讨会”顺利召开,会议围绕区块链治理全球发展现状、研究基础、发展趋势以及区块链行业应用创新展开研讨。北京大学陈钟教授做了“区块链治理与应用创…

消息队列的面试题

目录 面试题消息队列的使用场景场景描述与数据数据流程与具体数据优势与数据支持流量控制的举例场景:在线视频平台的直播流传输场景描述流量控制策略数据与效果 面试题 为什么使用消息队列? 消息队列有什么优点和缺点? Kafka、ActiveMQ、Rab…

opencv:基于阈值的分割方法(固定阈值和自适应阈值)

1、基于阈值的分割 (1)固定阈值分割 将图像分为两个部分:黑和白两个区域 /*author 还下着雨ZG * brief 固定阈值图像分割 * param[in] imSrc, 待分割的图像 * param[out] imSegment, 分割后的图像 * param[in] threVal, 输入的阈值 * return, 返回正整数表示图像…

Ubuntu设置时区

Ubuntu设置时区 在 Ubuntu 中设置时区可以通过以下几个步骤来完成: 方法一:使用命令行 查看当前时区设置: 可以使用以下命令查看当前系统的时区设置: timedatectl如果你想要详细信息,可以运行: timedatec…

ESP32-S3-DevKitC-1开发记录帖——与MPU6050进行姿态检测

目录 MPU6050传感器——姿态检测 1.姿态检测 1.1 基本认识 1)坐标系 2)姿态角的关系 3)陀螺仪检测的缺陷 4)利用加速度计检测角度 5)利用磁场检测角度 1.2 姿态融合与四元数 1.3传感器工作原理 1.4 MPU6050模…

【PyTorch】图像多分类项目

【PyTorch】图像二分类项目 【PyTorch】图像二分类项目-部署 【PyTorch】图像多分类项目 【PyTorch】图像多分类项目部署 多类图像分类的目标是为一组固定类别中的图像分配标签。 目录 加载和处理数据 搭建模型 定义损失函数 定义优化器 训练和迁移学习 用随机权重进行训…

新电脑如何设置 npm 源及查看源、安装 cnpm、pnpm 和 yarn 的详细教程

当你获得一台新电脑,或需要在现有电脑上优化 JavaScript 和 Node.js 的开发环境时,正确配置 npm 是一步不可少的过程。本教程将详细指导你如何设置 npm 源,查看当前源,以及如何安装 cnpm、pnpm 和 yarn。 1. 设置 npm 源 npm (N…

one-api 源码调试配置

本文主要介绍通过 VSCode 调试 one-api 源码。 一、环境配置 1.1 VSCode 和 one-api 安装 首先,确保已经安装了 VSCode(下载链接)和 one-api 源码(下载链接)已下载并安装了依赖 1.2 安装 Go 插件 在 VSCode 中,安装 Go 插件。 1.3 安装 dlv 调试包 可以通过下载源码…

【黑马java基础】多线程

什么是线程? 线程(Thread)是一个程序内部的一条执行流程。 这个是一条执行流程,虽然有循环,但是最后只有一条流程往前推进,所以视为一条。 程序中如果只有一条执行流程,那这个程序就是单线程的程序。 程序是指令序列…

Ubuntu20.04安装Elasticsearch

简介 ELK(Elasticsearch, Logstash, Kibana)是一套开源的日志管理和分析工具,用于收集、存储、分析和可视化日志数据。以下是如何在Ubuntu服务器上安装和配置ELK堆栈以便发送和分析日志信息的步骤。 安装Elasticsearch 首先,安…

vue3——利用自定义指令实现下拉框分页懒加载

需求:下拉框一开始请求第一页的内容,滚动到最后的时候,请求第二页的内容,如此反复,直到所有数据加载完成。 selectLoadMore.ts //自定义指令:实现下拉框下拉到末尾时,加载下一页的内容 // 使用…

【系统架构设计师】十八、架构设计实践(信息系统架构设计理论与实践2)

目录 四、企业信息系统的总体框架 4.1 战略系统 4.2 业务系统 4.3 应用系统 4.4 企业信息基础设施 4.5 业务流程重组BPR 4.6 业务流程管理BPM 五、信息系统架构设计方法 5.1 行业标准的体系架构框架 5.2 架构开发方法 5.3 信息化总体架构方法 5.4 信息化建设生命周…

防火墙——网络环境支持

目录 网络环境支持 防火墙的组网 web连接上防火墙 web管理口 让防火墙接到网络环境中 ​编辑 管理员用户管理 缺省管理员 接口 配置一个普通接口 创建安全区域 路由模式 透明模式 混合模式 防火墙的安全策略 防火墙转发流程 与传统包过滤的区别 创建安全策略 …

DDoS攻击:威胁与防护策略

DDoS(分布式拒绝服务)攻击是网络安全领域的一大挑战,对企业造成严重的影响。本文将深入探讨DDoS攻击的原理和防护方法。 DDoS攻击的原理 DDoS攻击通过大量请求,使目标系统无法响应正常请求。攻击者利用多台计算机发送大量请求&am…

气膜羽毛球馆的维护和运营成本解析—轻空间

随着人们对健康生活方式的追求不断增加,羽毛球这项运动也愈发受到欢迎。然而,传统的羽毛球馆往往存在建设周期长、成本高、维护复杂等问题。气膜羽毛球馆作为一种新型的运动场馆解决方案,因其快速搭建、环保节能、舒适环境等优势而逐渐被广泛…

跨平台桌面应用程序框架Electron

用于构建跨平台桌面应用程序的框架。Electron 由 GitHub 开发,它允许开发者使用 Web 技术(如 HTML、CSS 和 JavaScript)来创建桌面软件。Electron 基于 Node.js 和 Chromium,因此可以提供丰富的功能和性能。 Electron 的主要优点…

netty入门-5 ServerBootstrap与Bootstarp

前言 本来这篇应该紧接着说明Future和Promise。 但是考虑前文第三篇即用到了ServerBootstrap来启动一个服务器,并且我读的闪电侠netty,先写的服务器与客户端启动这部分。索性就先写出来了。主要内容来自闪电侠netty ServerBootstrap ServerBootstrap就…

LabVIEW和IQ测试仪进行WiFi测试

介绍一个使用LabVIEW和LitePoint IQxel-MW IQ测试仪进行WiFi测试的系统。包括具体的硬件型号、如何实现通讯、开发中需要注意的事项以及实现的功能。 使用的硬件​ IQ测试仪型号: LitePoint IQxel-MW 电脑: 配置高效的台式机或笔记本电脑 路由器: 支持802.11ax (Wi-Fi 6) 的…

C语言 | Leetcode C语言题解之第282题给表达式添加运算符

题目: 题解: #define MAX_COUNT 10000 // 解的个数足够大 #define NUM_COUNT 100 // 操作数的个数足够大 long long num[NUM_COUNT] {0};long long calc(char *a) { // 计算表达式a的值// 将数字和符号,入栈memset(num, 0, sizeof(num));in…