Python学习 - 爬虫系统架构设计

主要业务流程

  1. 初始请求
  2. 请求过滤器
  3. 请求队列
  4. 响应下载器
  5. 数据解析器
  6. 数据清洗器
  7. 存储器

设计图

爬虫系统设计.drawio.png

  • master + slave:master控制队列,过滤,传递任务;slave负责执行

    • 缺点:master和slave端交互数据频繁,slave的数据进出,都给master去调度,对master端相当于成倍数据,并发比较大
  • 升级策略2:分离响应异步下载与异步处理,避免一方阻塞另一方

    • 如果解析,和清洗也会处理很长时间,并发量就会下降,也可以在中间加入队列,解耦任务
      • 如果没有耗时操作,也没必要新加一个队列来做
      • 具体在哪些环节之间加入队列,取决你分析业务需求,在哪些环节会出现耗时操作
    • 对于一个任务来说,是共享一个进程的,这个队列可以直接用Queue(内存队列),共享一个进程中数据,
  • 升级策略3:日志监控捕获错误,并实时通报。ELK

    • 先对日志进行埋点,针对Error错误日志进行报告
  • 还有一种,master 只负责过滤重复请求;slave自己负责维护自己的队列,只需要 slave 执行任务前询问 master是否有重复值即可

    • 减轻了master的负担,但是slave自己维护自己队列,彼此独立

系统架构组件

  1. 队列组件

    • 队列类型
      • FIFO
    • 内存队列 - 一般实现单机版的队列
      • Python内置队列
      • Asyncio中的队列
    • 持久化队列:分布式,断点续爬
      • Redis队列
      • 消息队列:Kafka,Rabbitmq
  2. 过滤器组件

    • 指纹过滤器(redis等): 千万级数据去重
    • simhash过滤器,相似文本去重
    • 布隆过滤器(redis),亿级数据去重(存在极小概率误判),,占的空间比较小,性能高
  3. 下载器组件

    • urllib/requests
    • aiohttp
    • tomada.httpclient
  4. 异步组件

    • asyncio
    • celery + eventlet/gevent
    • selenium + chrome-headless Pool(多个浏览器实例)
    • appium + android-app Pool (多台设备)
  5. 数据解析提取组件

    • 语法规则
      • 正则
      • Xpath
    • 解析提取工具
      • re
      • lxml
      • lxml + bs4
      • lxml + pyquery
  6. 数据清洗组件

    • 自定义清洗规则
  7. 数据存储组件

    • 存储介质
      • file:csv/json
      • DB:mysql/mongondb
    • 存储工具
      • csv、json
      • sqlalchemy/mongoengine
  8. 程序监控组件

    • ELK
      • elasticsearch:日志数据存储
      • logstash: 日志收集工具
      • kibana: 日志可视化
  9. 可视化控制组件

    • web界面
    • GUI界面

异步改造并发代码

同步请求

  1. 下载器中,开始使用的是 requests 同步发请求,没有异步
  • 下载器(同步请求)
import requests
from spiderSystem.response import Responseclass RequestsDownloader(object):"""根据request发起请求,构建response对象"""def fetch(self, request):if request.method.upper() == "GET":resp = requests.get(request.with_query_url, headers=request.headers)elif request.method.upper() == "POST":resp = requests.post(request.with_query_url, headers=request.headers, body=request.body)else:raise Exception('only support GET or POST Method')return Response(request, status_code=resp.status_code, url=resp.url, headers=resp.headers, body=resp.content)
  • 请求的 Slave 客户端
from .request_manager import RequestManager
from .request_manager.utils.redis_tools import get_redis_queue_cls
from .downloader import RequestsDownloaderfrom .request import RequestFIFO_QUEUE = get_redis_queue_cls('fifo')class Slave(object):def __init__(self, spiders, project_name, request_manager_config):self.filter_queue = FIFO_QUEUE("filter_queue", host="localhost")self.request_manager = RequestManager(**request_manager_config) self.downloader = RequestsDownloader()   # 用 requests 同步请求的下载器self.spiders = spidersself.project_name = project_namedef handle_request(self):# 1. 获取一个请求request = self.request_manager.get_request(self.project_name)# 2. 发起请求response = self.downloader.fetch(request)  # 每次都同步去请求 !!!# 3. 获取爬虫对象spider = self.spiders[request.name]()# 4. 处理 responsefor result in spider.parse(response):if result is None:raise Exception('不允许返回None')elif isinstance(result, Request):self.filter_queue.put(result)else:# 意味着是一个数据new_result = spider.data_clean(result)spider.data_save(new_result)def run(self):while True:self.handle_request() 

异步请求改造

  • 通过 tornado 的异步请求
  1. 下载器(异步)
from tornado.httpclient import HTTPClient, HTTPRequest, AsyncHTTPClientfrom spiderSystem.response import Response# tornado 也有同步请求方式 (可以忽略)
class TornadoDownloader(object):def __init__(self):self.httpclient = HTTPClient()def fetch(self, request):print("tornado 同步客户端发的请求")tornado_request = HTTPRequest(request.with_query_url, method=request.method.upper(), headers=request.headers)tornado_response = self.httpclient.fetch(tornado_request)return Response(request=request, status_code=tornado_response.code, url=tornado_response.effective_url,body=tornado_response.buffer.read())"""同步的请求,不能复用,需要用完后关闭"""def __del__(self):self.httpclient.close()# tornado 也有异步请求方式
class AsyncTornadoDownloader(object):def __init__(self):self.async_http_client = AsyncHTTPClient()async def fetch(self, request): # 开启协程print("tornado 异步客户端发的请求")tornado_request = HTTPRequest(request.with_query_url, method=request.method.upper(), headers=request.headers)tornado_response = await self.async_http_client.fetch(tornado_request) # 等待return Response(request=request, status_code=tornado_response.code, url=tornado_response.effective_url,headers=request.headers,body=tornado_response.buffer.read())
  • Slave 调用方
import asyncio
import tornado.ioloopfrom .request_manager import RequestManager
from .request_manager.utils.redis_tools import get_redis_queue_cls
from .downloader import RequestsDownloader, TornadoDownloader, AsyncTornadoDownloaderfrom .request import RequestFIFO_QUEUE = get_redis_queue_cls('fifo')class Slave(object):def __init__(self, spiders, project_name, request_manager_config):self.filter_queue = FIFO_QUEUE("filter_queue", host="localhost")self.request_manager = RequestManager(**request_manager_config) self.downloader = AsyncTornadoDownloader()  # 异步下载器self.spiders = spidersself.project_name = project_nameasync def handle_request(self):# request = self.request_manager.get_request(self.project_name)  阻塞改异步io_loop = tornado.ioloop.IOLoop.current()# 1. 获取一个请求future = io_loop.run_in_executor(None, self.request_manager.get_request,self.project_name)  # 不支持协程的函数,可以自己获取事件循环,去定义执行,让其支持协程request = await future# 2. 发起请求response = await self.downloader.fetch(request)# 3. 获取爬虫对象spider = self.spiders[request.name]()# 4. 处理 responsefor result in spider.parse(response):if result is None:raise Exception('不允许返回None')elif isinstance(result, Request):# self.filter_queue.put(result)  可能阻塞,改异步await io_loop.run_in_executor(None, self.filter_queue.put,result)   else:# 意味着是一个数据new_result = spider.data_clean(result)spider.data_save(new_result)async def run(self):while True:# 不能写成 await self.handle_request(),否则,也是相当于同步请求了await asyncio.wait([self.handle_request(),self.handle_request(),])
  • 启动方式
if __name__ == '__main__':spiders = {BaiduSpider.name: BaiduSpider}# 同步请求,用 requests 发请求# Slave(spiders, project_name=PROJECT_NAME, request_manager_config=REQUEST_MANAGER_CONFIG).run()# 要用异步方式去请求slave = Slave(spiders, project_name=PROJECT_NAME, request_manager_config=REQUEST_MANAGER_CONFIG)io_loop = tornado.ioloop.IOLoop.current()io_loop.run_sync(slave.run)

tornado库 io_loop.run_sync 用于将阻塞函数转换为同步函数并在 IOLoop 上执行,它会阻塞当前协程。 io_loop.run_in_executor 用于在指定的线程池中异步执行耗时的、阻塞的操作,不会阻塞当前协程,并允许 IOLoop 继续处理其他事件。

asyncio库 实现类似于 run_sync 的效果:您可以使用 loop.run_until_complete 方法来运行一个协程并等待其完成。这个方法会阻塞当前线程,直到协程执行完毕 实现类似于 run_in_executor 的效果:您可以使用 loop.run_in_executor 方法将耗时的、阻塞的操作转移到一个线程池中执行,以避免阻塞事件循环。

async 异步协程改造重点!!!
  1. 下载器中,用到的所有异步的地方,必须是协程 async 定义
  2. await 后面跟着的,一定是支持协程的方法,要不是一个 协程对象,future 或者 task 对象,比如 self.async_http_client.fetch ,如果不支持协程,会报错
  3. 连带着的,所有调用 async 的方法,也必须是协程函数
  4. 对于不支持协程的函数,可以自己获取事件循环,去定义执行,让其支持协程;如果一个函数是一个协程函数后,如果这个协程函数中,有任意可以阻塞的,或耗时操作,都应该改成异步的 await ,不然可能会阻塞整个线程

# self.request_manager.get_request 本身不支持异步,或者改造成异步,嵌套要改的太深,可以用 io_loop.run_in_executor 来替代io_loop = tornado.ioloop.IOLoop.current()# 1. 获取一个请求future = io_loop.run_in_executor(None, self.request_manager.get_request,self.project_name) request = await future
  1. 在最开始调用的地方,比如 run ,启动的方式,必须是 用 asyncio.wait 或用其他方式启动(asyncio.gather 或 asyncio.as_completed)
# 开启2个协程,去执行。asyncio.wait 能让其变成一个异步关系
async def run(self):while True:# 不能写成 await self.handle_request(),否则,也是相当于同步请求了await asyncio.wait([self.handle_request(),self.handle_request(),])

Master 进程用多线程改造

  • master 的启动方法,这两个可以用两个线程去做,不然以前的写法是同步的执行方式
  def run(self):# self.run_start_requests()# self.run_filter_queue()# 两个线程去做threading.Thread(target=self.run_start_requests).start()threading.Thread(target=self.run_filter_queue).start()

自己封装的SpiderSystem模块安装成内置环境中

  1. 在模块目录添加 setup.py 脚本
├── setup.py
├── spiderSystem
├── README.md
  1. 执行 pip3 setup.py install 即可
  2. 查看包信息 pip3 show spiderSystem
from setuptools import setup, find_packagessetup(name="spiderSystem",version="0.1",description="spiderSystem module",author='raoju',url="url",license="license",packages=find_packages(exclude=[]), # 当前所有模块都安装install_requires=["tornado >= 5.1","pycurl",])

.markdown-body pre,.markdown-body pre>code.hljs{color:#333;background:#f8f8f8}.hljs-comment,.hljs-quote{color:#998;font-style:italic}.hljs-keyword,.hljs-selector-tag,.hljs-subst{color:#333;font-weight:700}.hljs-literal,.hljs-number,.hljs-tag .hljs-attr,.hljs-template-variable,.hljs-variable{color:teal}.hljs-doctag,.hljs-string{color:#d14}.hljs-section,.hljs-selector-id,.hljs-title{color:#900;font-weight:700}.hljs-subst{font-weight:400}.hljs-class .hljs-title,.hljs-type{color:#458;font-weight:700}.hljs-attribute,.hljs-name,.hljs-tag{color:navy;font-weight:400}.hljs-link,.hljs-regexp{color:#009926}.hljs-bullet,.hljs-symbol{color:#990073}.hljs-built_in,.hljs-builtin-name{color:#0086b3}.hljs-meta{color:#999;font-weight:700}.hljs-deletion{background:#fdd}.hljs-addition{background:#dfd}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}

主要业务流程

  1. 初始请求
  2. 请求过滤器
  3. 请求队列
  4. 响应下载器
  5. 数据解析器
  6. 数据清洗器
  7. 存储器

设计图

爬虫系统设计.drawio.png

  • master + slave:master控制队列,过滤,传递任务;slave负责执行

    • 缺点:master和slave端交互数据频繁,slave的数据进出,都给master去调度,对master端相当于成倍数据,并发比较大
  • 升级策略2:分离响应异步下载与异步处理,避免一方阻塞另一方

    • 如果解析,和清洗也会处理很长时间,并发量就会下降,也可以在中间加入队列,解耦任务
      • 如果没有耗时操作,也没必要新加一个队列来做
      • 具体在哪些环节之间加入队列,取决你分析业务需求,在哪些环节会出现耗时操作
    • 对于一个任务来说,是共享一个进程的,这个队列可以直接用Queue(内存队列),共享一个进程中数据,
  • 升级策略3:日志监控捕获错误,并实时通报。ELK

    • 先对日志进行埋点,针对Error错误日志进行报告
  • 还有一种,master 只负责过滤重复请求;slave自己负责维护自己的队列,只需要 slave 执行任务前询问 master是否有重复值即可

    • 减轻了master的负担,但是slave自己维护自己队列,彼此独立

系统架构组件

  1. 队列组件

    • 队列类型
      • FIFO
    • 内存队列 - 一般实现单机版的队列
      • Python内置队列
      • Asyncio中的队列
    • 持久化队列:分布式,断点续爬
      • Redis队列
      • 消息队列:Kafka,Rabbitmq
  2. 过滤器组件

    • 指纹过滤器(redis等): 千万级数据去重
    • simhash过滤器,相似文本去重
    • 布隆过滤器(redis),亿级数据去重(存在极小概率误判),,占的空间比较小,性能高
  3. 下载器组件

    • urllib/requests
    • aiohttp
    • tomada.httpclient
  4. 异步组件

    • asyncio
    • celery + eventlet/gevent
    • selenium + chrome-headless Pool(多个浏览器实例)
    • appium + android-app Pool (多台设备)
  5. 数据解析提取组件

    • 语法规则
      • 正则
      • Xpath
    • 解析提取工具
      • re
      • lxml
      • lxml + bs4
      • lxml + pyquery
  6. 数据清洗组件

    • 自定义清洗规则
  7. 数据存储组件

    • 存储介质
      • file:csv/json
      • DB:mysql/mongondb
    • 存储工具
      • csv、json
      • sqlalchemy/mongoengine
  8. 程序监控组件

    • ELK
      • elasticsearch:日志数据存储
      • logstash: 日志收集工具
      • kibana: 日志可视化
  9. 可视化控制组件

    • web界面
    • GUI界面

异步改造并发代码

同步请求

  1. 下载器中,开始使用的是 requests 同步发请求,没有异步
  • 下载器(同步请求)
import requests
from spiderSystem.response import Responseclass RequestsDownloader(object):"""根据request发起请求,构建response对象"""def fetch(self, request):if request.method.upper() == "GET":resp = requests.get(request.with_query_url, headers=request.headers)elif request.method.upper() == "POST":resp = requests.post(request.with_query_url, headers=request.headers, body=request.body)else:raise Exception('only support GET or POST Method')return Response(request, status_code=resp.status_code, url=resp.url, headers=resp.headers, body=resp.content)
  • 请求的 Slave 客户端
from .request_manager import RequestManager
from .request_manager.utils.redis_tools import get_redis_queue_cls
from .downloader import RequestsDownloaderfrom .request import RequestFIFO_QUEUE = get_redis_queue_cls('fifo')class Slave(object):def __init__(self, spiders, project_name, request_manager_config):self.filter_queue = FIFO_QUEUE("filter_queue", host="localhost")self.request_manager = RequestManager(**request_manager_config) self.downloader = RequestsDownloader()   # 用 requests 同步请求的下载器self.spiders = spidersself.project_name = project_namedef handle_request(self):# 1. 获取一个请求request = self.request_manager.get_request(self.project_name)# 2. 发起请求response = self.downloader.fetch(request)  # 每次都同步去请求 !!!# 3. 获取爬虫对象spider = self.spiders[request.name]()# 4. 处理 responsefor result in spider.parse(response):if result is None:raise Exception('不允许返回None')elif isinstance(result, Request):self.filter_queue.put(result)else:# 意味着是一个数据new_result = spider.data_clean(result)spider.data_save(new_result)def run(self):while True:self.handle_request() 

异步请求改造

  • 通过 tornado 的异步请求
  1. 下载器(异步)
from tornado.httpclient import HTTPClient, HTTPRequest, AsyncHTTPClientfrom spiderSystem.response import Response# tornado 也有同步请求方式 (可以忽略)
class TornadoDownloader(object):def __init__(self):self.httpclient = HTTPClient()def fetch(self, request):print("tornado 同步客户端发的请求")tornado_request = HTTPRequest(request.with_query_url, method=request.method.upper(), headers=request.headers)tornado_response = self.httpclient.fetch(tornado_request)return Response(request=request, status_code=tornado_response.code, url=tornado_response.effective_url,body=tornado_response.buffer.read())"""同步的请求,不能复用,需要用完后关闭"""def __del__(self):self.httpclient.close()# tornado 也有异步请求方式
class AsyncTornadoDownloader(object):def __init__(self):self.async_http_client = AsyncHTTPClient()async def fetch(self, request): # 开启协程print("tornado 异步客户端发的请求")tornado_request = HTTPRequest(request.with_query_url, method=request.method.upper(), headers=request.headers)tornado_response = await self.async_http_client.fetch(tornado_request) # 等待return Response(request=request, status_code=tornado_response.code, url=tornado_response.effective_url,headers=request.headers,body=tornado_response.buffer.read())
  • Slave 调用方
import asyncio
import tornado.ioloopfrom .request_manager import RequestManager
from .request_manager.utils.redis_tools import get_redis_queue_cls
from .downloader import RequestsDownloader, TornadoDownloader, AsyncTornadoDownloaderfrom .request import RequestFIFO_QUEUE = get_redis_queue_cls('fifo')class Slave(object):def __init__(self, spiders, project_name, request_manager_config):self.filter_queue = FIFO_QUEUE("filter_queue", host="localhost")self.request_manager = RequestManager(**request_manager_config) self.downloader = AsyncTornadoDownloader()  # 异步下载器self.spiders = spidersself.project_name = project_nameasync def handle_request(self):# request = self.request_manager.get_request(self.project_name)  阻塞改异步io_loop = tornado.ioloop.IOLoop.current()# 1. 获取一个请求future = io_loop.run_in_executor(None, self.request_manager.get_request,self.project_name)  # 不支持协程的函数,可以自己获取事件循环,去定义执行,让其支持协程request = await future# 2. 发起请求response = await self.downloader.fetch(request)# 3. 获取爬虫对象spider = self.spiders[request.name]()# 4. 处理 responsefor result in spider.parse(response):if result is None:raise Exception('不允许返回None')elif isinstance(result, Request):# self.filter_queue.put(result)  可能阻塞,改异步await io_loop.run_in_executor(None, self.filter_queue.put,result)   else:# 意味着是一个数据new_result = spider.data_clean(result)spider.data_save(new_result)async def run(self):while True:# 不能写成 await self.handle_request(),否则,也是相当于同步请求了await asyncio.wait([self.handle_request(),self.handle_request(),])
  • 启动方式
if __name__ == '__main__':spiders = {BaiduSpider.name: BaiduSpider}# 同步请求,用 requests 发请求# Slave(spiders, project_name=PROJECT_NAME, request_manager_config=REQUEST_MANAGER_CONFIG).run()# 要用异步方式去请求slave = Slave(spiders, project_name=PROJECT_NAME, request_manager_config=REQUEST_MANAGER_CONFIG)io_loop = tornado.ioloop.IOLoop.current()io_loop.run_sync(slave.run)

tornado库 io_loop.run_sync 用于将阻塞函数转换为同步函数并在 IOLoop 上执行,它会阻塞当前协程。 io_loop.run_in_executor 用于在指定的线程池中异步执行耗时的、阻塞的操作,不会阻塞当前协程,并允许 IOLoop 继续处理其他事件。

asyncio库 实现类似于 run_sync 的效果:您可以使用 loop.run_until_complete 方法来运行一个协程并等待其完成。这个方法会阻塞当前线程,直到协程执行完毕 实现类似于 run_in_executor 的效果:您可以使用 loop.run_in_executor 方法将耗时的、阻塞的操作转移到一个线程池中执行,以避免阻塞事件循环。

async 异步协程改造重点!!!
  1. 下载器中,用到的所有异步的地方,必须是协程 async 定义
  2. await 后面跟着的,一定是支持协程的方法,要不是一个 协程对象,future 或者 task 对象,比如 self.async_http_client.fetch ,如果不支持协程,会报错
  3. 连带着的,所有调用 async 的方法,也必须是协程函数
  4. 对于不支持协程的函数,可以自己获取事件循环,去定义执行,让其支持协程;如果一个函数是一个协程函数后,如果这个协程函数中,有任意可以阻塞的,或耗时操作,都应该改成异步的 await ,不然可能会阻塞整个线程

# self.request_manager.get_request 本身不支持异步,或者改造成异步,嵌套要改的太深,可以用 io_loop.run_in_executor 来替代io_loop = tornado.ioloop.IOLoop.current()# 1. 获取一个请求future = io_loop.run_in_executor(None, self.request_manager.get_request,self.project_name) request = await future
  1. 在最开始调用的地方,比如 run ,启动的方式,必须是 用 asyncio.wait 或用其他方式启动(asyncio.gather 或 asyncio.as_completed)
# 开启2个协程,去执行。asyncio.wait 能让其变成一个异步关系
async def run(self):while True:# 不能写成 await self.handle_request(),否则,也是相当于同步请求了await asyncio.wait([self.handle_request(),self.handle_request(),])

Master 进程用多线程改造

  • master 的启动方法,这两个可以用两个线程去做,不然以前的写法是同步的执行方式
  def run(self):# self.run_start_requests()# self.run_filter_queue()# 两个线程去做threading.Thread(target=self.run_start_requests).start()threading.Thread(target=self.run_filter_queue).start()

自己封装的SpiderSystem模块安装成内置环境中

  1. 在模块目录添加 setup.py 脚本
├── setup.py
├── spiderSystem
├── README.md
  1. 执行 pip3 setup.py install 即可
  2. 查看包信息 pip3 show spiderSystem
from setuptools import setup, find_packagessetup(name="spiderSystem",version="0.1",description="spiderSystem module",author='raoju',url="url",license="license",packages=find_packages(exclude=[]), # 当前所有模块都安装install_requires=["tornado >= 5.1","pycurl",])

如果你对Python感兴趣,想要学习python,这里给大家分享一份Python全套学习资料,都是我自己学习时整理的,希望可以帮到你,一起加油!

😝有需要的小伙伴,可以点击下方链接免费领取或者V扫描下方二维码免费领取🆓
Python全套学习资料

在这里插入图片描述

1️⃣零基础入门

① 学习路线

对于从来没有接触过Python的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。
在这里插入图片描述

② 路线对应学习视频

还有很多适合0基础入门的学习视频,有了这些视频,轻轻松松上手Python~
在这里插入图片描述

③练习题

每节视频课后,都有对应的练习题哦,可以检验学习成果哈哈!
在这里插入图片描述

2️⃣国内外Python书籍、文档

① 文档和书籍资料

在这里插入图片描述

3️⃣Python工具包+项目源码合集

①Python工具包

学习Python常用的开发软件都在这里了!每个都有详细的安装教程,保证你可以安装成功哦!
在这里插入图片描述

②Python实战案例

光学理论是没用的,要学会跟着一起敲代码,动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。100+实战案例源码等你来拿!
在这里插入图片描述

③Python小游戏源码

如果觉得上面的实战案例有点枯燥,可以试试自己用Python编写小游戏,让你的学习过程中增添一点趣味!
在这里插入图片描述

4️⃣Python面试题

我们学会了Python之后,有了技能就可以出去找工作啦!下面这些面试题是都来自阿里、腾讯、字节等一线互联网大厂,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。
在这里插入图片描述
在这里插入图片描述

上述所有资料 ⚡️ ,朋友们如果有需要的,可以扫描下方👇👇👇二维码免费领取🆓
在这里插入图片描述

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

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

相关文章

图文证明 牛顿-莱布尼茨公式

牛顿-莱布尼茨公式 牛顿-莱布尼茨公式是微积分中的基本定理之一,它描述了函数的导数和不定积分之间的关系。 该公式通常用来计算定积分。设函数f(x)在区间[a, b]上连续,且F(x)是f(x)在该区间上的一个原函数 即F’(x) f(x)。则牛顿-莱布尼茨公式表示为&…

【AIGC-图片生成视频系列-2】八仙过海,各显神通:AI生成视频相关汇总剖析

最近「图片生成视频系列」层出不穷,我拜读并结合实践(对,就是手撕代码,有开源就撕),并对以下几篇文章的相似点以及关键点稍微做个总结: 一. 生成视频中图像的一致性 在图像生成视频的这个过程…

提升CSC加分项|高职教师赴新西兰惠灵顿维多利亚大学访学交流

S老师科研背景条件一般,担心无法获得邀请函及通过CSC审批。我们建议:1.以加强国际合作和跨学科合作的方式,增强高职院校的影响力,为CSC评审提供加分项;2.同时申报4月份的国家公派和5月份的西部/地方合作项目&#xff0…

Java进阶(第八期): Java中递归的的使用和递归解决一些算法问题 Java中的异常机制、异常的处理逻辑 自定义异常

文章目录 一、递归1.1 递归的介绍1.2 递归的简单练习1.3 图解递归执行流程:1.4 使用递归完成悲波那契数列1.5 猴子吃桃子问题 二、异常三 、异常的处理逻辑3.1 try catch 捕获异常3.2 throws抛出异常 四、自定义异常 Java进阶(第八期) 一、递…

2、gdb常用功能2

1.4、线程 程序避免不了涉及到多线程.常用指令如下. 命令简写形式说明info thread显示当前进程内所有线程信息thread 切换到num线程thread find 寻找regexp在gdb中的idinfo address 结合上述图片理解,第一列的id是gdb内部为线程排序的一个id,第三列中…

行人重识别(ReID)基础知识入门

这里写目录标题 1、ReID技术概述1.1 基本原理1.2 实现流程1.3 重识别存在的技术挑战 2、训练数据格式介绍 1、ReID技术概述 1.1 基本原理 ReID,全称Re-identification,目的是利用各种智能算法在图像数据库中找到与要搜索的目标相似的对象。ReID是图像检…

Eureka服务注册与发现

1. Eureka简介 Eureka采用了CS的设计架构,Eureka Server 作为服务注册功能的服务器,它是服务注册中心。而系统中的其他微服务,使用 Eureka的客户端连接到 Eureka Server并维持心跳连接。这样系统的维护人员就可以通过 Eureka Server 来监控系…

三个故事,谈谈小米汽车技术发布会

都说新年新气象,随着年末消费旺季到来,汽车市场越来越热闹了。 继蔚来12月23日公布旗舰车型ET9,华为26日发布问界M9,小米汽车首款量产车型SU7终于正式亮相。 12月28日,在小米汽车技术发布会上,小米创办人…

CCNP课程实验-Route_Path_Control_CFG

目录 实验条件网络拓朴需求 配置实现基础配置需求实现1.A---F所有区用Loopback模拟,地址格式为:XX.XX.XX.XX/32,其中X为路由器编号。根据拓扑宣告进对应协议。A1和A2区为特例,A1:55.55.55.0/24,A2&#xff…

【数学建模美赛M奖速成系列】Matplotlib绘图技巧(二)

Matplotlib绘图技巧(二) 写在前面2. 函数间区域填充函数fill_between()和fill()参数: 3. 散点图 scatter4. 直方图 hist5. 条形图 bar5.1 一个数据样本的条形图参数: 5.2 多个数据样本进行对比的直方图5.3 水平条形图参数 5.4 绘制…

Vue3-31-路由-RouterView的name属性的作用

作用描述 <router-view> 标签是用来渲染路由对应的组件的位置&#xff1b; 默认情况下&#xff0c;一个路由是只对应一个组件的。 但是&#xff0c;可以通过给 <router-view> 指定 name 属性的方式&#xff0c;实现同时渲染多个组件的效果。 这也叫做 命名视图。 注…

《企业数据资源相关会计处理暂行规定》学习笔记

附&#xff1a;2023年数据资源入表白皮书下载&#xff1a; 关注WX公众号&#xff1a; commindtech77&#xff0c; 获得数据资产相关白皮书下载地址 1. 回复关键字&#xff1a;数据资源入表白皮书 下载 《2023数据资源入表白皮书》 2. 回复关键字&#xff1a;光大银行 下载 光…

云安全是什么?有什么作用

随着云计算的普及和深入应用&#xff0c;云安全已成为企业和组织面临的重要挑战。云安全旨在保护云计算环境中的数据、应用程序和基础设施免受各种威胁和攻击&#xff0c;确保云计算环境的可用性、机密性和完整性。 云安全包括以下几个关键领域&#xff1a; 一、数据保护 数据…

用 Node.js 写一个爬虫

自己设计一个网站&#xff0c;然后去爬取别人家页面的数据来做一个自己的网站。哈哈哈&#xff0c;如果自己写着玩可能没啥事&#xff0c;但如果用这个网站来获利&#xff0c;你可能就要被寄律师函了&#xff0c;毕竟这有点‘刑’。这篇文章呢&#xff0c;就带大家爬取豆瓣TOP2…

C++图论之强连通图

1. 连通性 什么是连通性&#xff1f; 连通&#xff0c;字面而言&#xff0c;类似于自来水管道中的水流&#xff0c;如果水能从某一个地点畅通流到另一个地点&#xff0c;说明两点之间是连通的。也说明水管具有连通性&#xff0c;图中即如此。 无向图和有向图的连通概念稍有差…

LAMP集中式搭建+LNMP分布式搭建(新版)

LAMP搭建LNMP搭建 LAMP搭建LNMP搭建一、LAMP搭建(集中式)1、LAMP简介2、LAMP组件及作用3、编译安装Apache httpd服务4、编译安装mysqld 服务5、编译安装PHP解析环境6、安装论坛7、安装博客 二、LNMP搭建(分布式)1、LNMP工作原理2、安装nginx3、安装mysql4、安装php5、在浏览器测…

《深入理解Java虚拟机(第三版)》读书笔记:虚拟机类加载机制、虚拟机字节码执行引擎、编译与优化

下文是阅读《深入理解Java虚拟机&#xff08;第3版&#xff09;》这本书的读书笔记&#xff0c;如有侵权&#xff0c;请联系删除。 文章目录 第6章 类文件结构第7章 虚拟机类加载机制7.2 类加载的时机7.3 类加载的过程7.4 类加载器7.5 Java模块化系统 第8章 虚拟机字节码执…

C++求解数组长度的方法(包含求解vector和字符串求解的方法)

对于一个C的初学者&#xff0c;在如何求解数组长度问题上可能会稍有混乱&#xff0c;因为求解长度的方法有很多&#xff0c;比如size()、length()、sizeof()等函数&#xff0c;今天我就和大家一起学习如何求解数组长度&#xff0c;并探讨size()、length()、sizeof()这三个函数的…

【Linux驱动】设备树简介 | 内核对设备树的处理

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《Linux驱动》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 目录 &#x1f9f2;设备树简介&#x1f3f9;设备树语法&#x1f3f9;常见节点和属性&#x1f3f9…

LOAM: Lidar Odometry and Mapping in Real-time 论文阅读

论文链接 LOAM: Lidar Odometry and Mapping in Real-time 0. Abstract 提出了一种使用二维激光雷达在6自由度运动中的距离测量进行即时测距和建图的方法 距离测量是在不同的时间接收到的&#xff0c;并且运动估计中的误差可能导致生成的点云的错误配准 本文的方法在不需要高…