【python自动化】playwright长截图切换标签页JS注入实战

news2024/10/7 20:27:00

前言

当前教程使用的playwright版本为1.37.0,selenium版本为3.141.0

官方文档:https://playwright.dev/python/docs/screenshots

本教程目录如下

文章目录

    • 前言
    • playwright各类截图源码阅读
      • ElementHandle类下的截图
      • Page类下的截图
      • Locator类下的截图
    • Playwright快速使用截图功能
    • 两大框架标签页切换对比
      • selenium切换标签页
      • playwright切换标签页
      • playwright切换标签页代码封装
    • JS注入
      • selenium使用js注入
      • playwright使用js注入
    • 综合实战
      • **实战需求**
      • **难点**
      • **解决方案**
      • 图像拼接封装
    • 实战完整代码

playwright各类截图源码阅读

通过阅读源码:playwright -> sync_api -> _generated.py可知,可以在以下三种方式下进行screenshots截图。

返回值均为字节bytes

class ElementHandle(JSHandle):(官方不建议或弃用)
	def screenshot

class Page(SyncContextManager):(官方推荐整个页面截图)
	def screenshot

class Locator(SyncBase):(官方推荐元素定位截图)
	def screenshot

ElementHandle类下的截图

官方建议不要用此方式,请使用Locator对象进行操作,后续可能会弃用此方式。

该方法会截取页面的屏幕截图,并根据该特定元素的大小和位置进行裁剪。如果该元素被其他元素覆盖,则在截图上实际上不可见。如果该元素是可滚动容器,则截图上只会显示当前滚动的内容。该方法在进行屏幕截图之前会等待 可操作性 检查,然后将元素滚动到视图中。如果该元素从 DOM 中分离,该方法将抛出错误。

用法

element_handle.screenshot()
element_handle.screenshot(**kwargs)

参数

参数类型含义
timeoutUnion[float, None]最大等待时间,以毫秒为单位。默认为30000(30秒)。传入0以禁用超时。browser_context.set_default_timeout()page.set_default_timeout()方法更改默认值。
typeUnion[“jpeg”, “png”, None]指定截图的类型,默认为png。
pathUnion[pathlib.Path, str, None]图像保存的文件路径。截图类型将根据文件扩展名进行推断。如果path是相对路径,则相对于当前工作目录解析。如果不提供路径,则图像将不会保存到磁盘。
qualityUnion[int, None]图像的质量,介于0到100之间。不适用于png图像。
omit_backgroundUnion[bool, None]隐藏默认的白色背景,允许使用透明度进行截图。不适用于jpeg图像。默认为false
animationsUnion[“allow”, “disabled”, None]设置为"disabled"时,停止CSS动画、CSS过渡和Web动画。动画的处理方式取决于其持续时间:有限动画将快进到完成状态,因此它们会触发transitionend事件。 无限动画将取消到初始状态,然后在截图后重新播放。默认为"allow",即保持动画不变。
caretUnion[“hide”, “initial”, None]设置为"hide"时,截图将隐藏文本插入符。设置为"initial"时,文本插入符的行为不会改变。默认为"hide"
scaleUnion[“css”, “device”, None]设置为"css"时,截图上每个CSS像素将具有一个实际像素。对于高DPI设备,这将使截图保持较小的大小。使用"device"选项将使每个设备像素有一个实际像素,因此高DPI设备的截图将是两倍或更大。默认为"device"
maskUnion[List[Locator], None]指定在截图时应隐藏的定位符。被隐藏的元素将被叠加一个粉色框#FF00FF(由maskColor自定义),完全覆盖其边界框。
mask_colorUnion[str, None]指定被隐藏元素的覆盖框的颜色,以CSS颜色格式表示。默认颜色为粉色#FF00FF

Page类下的截图

用法

page.screenshot()
page.screenshot(**kwargs)

参数

参数类型含义
timeoutUnion[float, None]最大等待时间,以毫秒为单位。默认为30000(30秒)。传入0以禁用超时。browser_context.set_default_timeout()page.set_default_timeout()方法更改默认值。
typeUnion[“jpeg”, “png”, None]指定截图的类型,默认为png。
pathUnion[pathlib.Path, str, None]图像保存的文件路径。截图类型将根据文件扩展名进行推断。如果path是相对路径,则相对于当前工作目录解析。如果不提供路径,则图像将不会保存到磁盘。
qualityUnion[int, None]图像的质量,介于0到100之间。不适用于png图像。
omit_backgroundUnion[bool, None]隐藏默认的白色背景,允许使用透明度进行截图。不适用于jpeg图像。默认为false
full_pageUnion[bool, None]true时,截取完整可滚动页面的屏幕截图,而不是当前可见的视口。默认为false
clipUnion[{x: float, y: float, width: float, height: float}, None]指定结果图像的裁剪区域的对象。
animationsUnion[“allow”, “disabled”, None]设置为"disabled"时,停止CSS动画、CSS过渡和Web动画。动画的处理方式取决于其持续时间:有限动画将快进到完成状态,因此它们会触发transitionend事件。 无限动画将取消到初始状态,然后在截图后重新播放。默认为"allow",即保持动画不变。
caretUnion[“hide”, “initial”, None]设置为"hide"时,截图将隐藏文本插入符。设置为"initial"时,文本插入符的行为不会改变。默认为"hide"
scaleUnion[“css”, “device”, None]设置为"css"时,截图上每个CSS像素将具有一个实际像素。对于高DPI设备,这将使截图保持较小的大小。使用"device"选项将使每个设备像素有一个实际像素,因此高DPI设备的截图将是两倍或更大。默认为"device"
maskUnion[List[Locator], None]指定在截图时应隐藏的定位符。被隐藏的元素将被叠加一个粉色框#FF00FF(由maskColor自定义),完全覆盖其边界框。
mask_colorUnion[str, None]指定被隐藏元素的覆盖框的颜色,以CSS颜色格式表示。默认颜色为粉色#FF00FF

Locator类下的截图

该方法将截取页面的屏幕截图,并根据定位符匹配的特定元素的大小和位置进行裁剪。如果该元素被其他元素覆盖,则在截图上实际上不可见。如果该元素是可滚动容器,则截图上只会显示当前滚动的内容。

该方法会等待可操作性检查,然后将元素滚动到视图中,然后再进行截图。如果该元素已从 DOM 中移除,则该方法会抛出一个错误。

用法

page.get_by_role("link").screenshot()
page.locator("#main-content").screenshot()

参数

参数类型含义
timeoutUnion[float, None]最大等待时间,以毫秒为单位。默认为30000(30秒)。传入0以禁用超时。browser_context.set_default_timeout()page.set_default_timeout()方法更改默认值。
typeUnion[“jpeg”, “png”, None]指定截图的类型,默认为png。
pathUnion[pathlib.Path, str, None]图像保存的文件路径。截图类型将根据文件扩展名进行推断。如果path是相对路径,则相对于当前工作目录解析。如果不提供路径,则图像将不会保存到磁盘。
qualityUnion[int, None]图像的质量,介于0到100之间。不适用于png图像。
omit_backgroundUnion[bool, None]隐藏默认的白色背景,允许使用透明度进行截图。不适用于jpeg图像。默认为false
animationsUnion[“allow”, “disabled”, None]设置为"disabled"时,停止CSS动画、CSS过渡和Web动画。动画的处理方式取决于其持续时间:有限动画将快进到完成状态,因此它们会触发transitionend事件。 无限动画将取消到初始状态,然后在截图后重新播放。默认为"allow",即保持动画不变。
caretUnion[“hide”, “initial”, None]设置为"hide"时,截图将隐藏文本插入符。设置为"initial"时,文本插入符的行为不会改变。默认为"hide"
scaleUnion[“css”, “device”, None]设置为"css"时,截图上每个CSS像素将具有一个实际像素。对于高DPI设备,这将使截图保持较小的大小。使用"device"选项将使每个设备像素有一个实际像素,因此高DPI设备的截图将是两倍或更大。默认为"device"
maskUnion[List[Locator], None]指定在截图时应隐藏的定位符。被隐藏的元素将被叠加一个粉色框#FF00FF(由maskColor自定义),完全覆盖其边界框。
mask_colorUnion[str, None]指定被隐藏元素的覆盖框的颜色,以CSS颜色格式表示。默认颜色为粉色#FF00FF

注意点

locator类下的截图方法,是比page类下的截图方法少了两个可选参数。

full_page:对于元素截图不支持全页面滚动长截图。

clip:对于元素截图不支持裁剪。

Playwright快速使用截图功能

当前页面截图

page.screenshot(path="screenshot.png")

当前页面长截图

page.screenshot(path="screenshot.png", full_page=True)

将截图转为字节存储在缓存中

screenshot_bytes = page.screenshot()
print(base64.b64encode(screenshot_bytes).decode())

根据元素截图

page.locator(".header").screenshot(path="screenshot.png")

两大框架标签页切换对比

在Web UI测试中,我们点击某个带有超链接的元素,可能会在新的标签页打开。

实际上有时候浏览器还是停留在当前页面,并没有自己切到新页面,这时候就需要切换到新的标签页进行元素定位等相关操作。

selenium切换标签页

在selenium是通过handles句柄的方式进行切换。每个页面都有唯一的句柄,最新的页面可通过下标[-1]获取。

driver.switch_to.window(driver.window_handles[-1])

playwright切换标签页

在playwright的page类下有个将页面置于最前面(激活选项卡)方法,可以将目标标签页激活,并且在目标标签页进行元素定位等相关操作。

官方文档:https://playwright.dev/python/docs/api/class-page#page-bring-to-front

# 用法如下
Page.bring_to_front()

如何激活我们所需要激活的页面?

1、通过url

page.url

2、通过title

page.title

playwright切换标签页代码封装

个人感觉切换标签页selenium更方便一点,playwright需要我们自己封装一下。我封装的代码如下:

def switch_to_page(context: BrowserContext, url: str = None, title: str = None) -> Page:
    """
    切换到指定url
    :param context:传入一个浏览器上下文
    :param title: 当前标签页的标题
    :param url: 当前标签页的url
    :return: label_page:Page对象 返回对应的标签页,如果没找到则返回最新的标签页
    """
    for label_page in context.pages:
        if url:
            if url in label_page.url:
                label_page.bring_to_front()
                return label_page
        elif title:
            if title in label_page.title():
                label_page.bring_to_front()
                return label_page
    else:
        if title:
            print(f"没有找到【{title}】标题的标签页")
        if url:
            print(f"没有找到【{url}】网址的标签页")
    return context.pages[-1]

代码注释都写的很清楚了,这里就不单独做解析了。

JS注入

在一些特殊的情况下,我们需要执行原生js,从而达到我们一些框架无法完成的操作。

selenium使用js注入

使用execute_script方法

def execute_script(self, script, *args):
    """
    在当前窗口/框架中同步执行JavaScript。

    :参数:
     - script: 可执行的JavaScript脚本.
     - \*args: 任何适用的JavaScript参数.

    :使用方法:
     driver.execute_script('return document.title;')
    """

实战示列

我要通过js在浏览器创建一个新标签并打开我博客首页。

from selenium import webdriver
driver = webdriver.Chrome()
driver.execute_script(f'window.open("https://blog.csdn.net/qq_46158060", "_blank");')

playwright使用js注入

官方文档:https://playwright.dev/python/docs/api/class-page#page-evaluate

使用evaluate方法或evaluate_handle方法。

page.evaluate() 和 page.evaluate_handle() 之间的唯一区别是 page.evaluate_handle() 返回 JSHandle。

def evaluate(
        self, expression: str, arg: typing.Optional[typing.Any] = None
    ) -> typing.Any:

传入的是一个表达式,返回一个序列化值。

官方有挺多个示列。

```py
result = await page.evaluate(\"([x, y]) => Promise.resolve(x * y)\", [7, 8])
print(result) # prints \"56\"
```

```py
result = page.evaluate(\"([x, y]) => Promise.resolve(x * y)\", [7, 8])
print(result) # prints \"56\"
```

A string can also be passed in instead of a function:

```py
print(await page.evaluate(\"1 + 2\")) # prints \"3\"
x = 10
print(await page.evaluate(f\"1 + {x}\")) # prints \"11\"
```

```py
print(page.evaluate(\"1 + 2\")) # prints \"3\"
x = 10
print(page.evaluate(f\"1 + {x}\")) # prints \"11\"
```

实战示列(1)

我要通过js在浏览器创建一个新标签并打开我博客首页。

page.evaluate(f'window.open("https://blog.csdn.net/qq_46158060", "_blank");')

实战示列(2)

通过js定位一个id为main-content的元素,并且滚动该元素。

js = 'document.getElementById("main-content").scrollTo(600,800)'
page.evaluate(js)
# 或
# page.evaluate_handle(js)

综合实战

需要操作的页面如下

在这里插入图片描述

实战需求

1、使用playwright连接本地指定端口浏览器

2、通过浏览器在新标签页打开指定项目ID下的相关页面

3、页面分为左右两栏,可以分别滚动,需要滚动右侧栏,并且进行长截图

4、要求一个页面只能有一张图

难点

1、playwright如何连接本地指定端口浏览器进行操作

2、前文中提到,页面截图,默认是第一个滚动条(暂未找到切换滚动条方案),这里需要定位右侧栏,也就是第二个滚动条

3、执行playwright按键操作进行滚动,默认是第一个滚动条,需要结合多种定位和键位,操作复杂

4、前文中提到,如果通过定位右侧栏大框元素进行截图,只能固定截图,无法长截图

解决方案

1、playwright连接本地浏览器详细教程参考我之前写过的文章:playwright连接已有浏览器操作

2、使用js定位右侧框的元素

3、使用js定位右侧框的元素进而执行滚动操作

4、通过js滚动进行多次截图。每滚动一次截图一次,至于滚动的范围需要自己先进行调试,最后将多张图进行拼接成一张图片。

图片拼接技术参考之前文章:web自动化之selenium的特殊用法汇总篇 , 这篇文章的特殊网页无法长截图,使用多图拼接技术章节。

图像拼接封装

下载三方库

pip install pillow==8.4.0

封装代码

from PIL import Image
# 拼接图片的代码
def stitch_images(imgPath_1: str, imgPath_2: str, newImgPath: str) -> str:
    """
    :param imgPath_1: 第一张图片的路径,
    :param imgPath_2: 第二张图片的路径,
    :param newImgPath: 拼接图片的路径,
    :return: newImgPath
    """
    # 获取JPG、png图像的路径
    im_list_1 = [imgPath_1, imgPath_2]
    im_list = [Image.open(fn) for fn in im_list_1]
    # 图片转化为相同的尺寸
    ims = []
    for i in im_list:
        new_img = i.resize((1920, 961), Image.BILINEAR)
        ims.append(new_img)
    # 单幅图像尺寸
    width, height = ims[0].size
    # 创建空白长图
    result = Image.new(ims[0].mode, (width, height * len(ims)))
    # 拼接图片
    for i, im in enumerate(ims):
        result.paste(im, box=(0, i * height))
    # 保存图片
    result.save(newImgPath)
    return newImgPath

实战完整代码

步骤:

1、使用playwright连接本地浏览器(含用户数据,免登陆,懒加载)

2、使用js在新标签页打开相关网址

3、切换至指定标签页

4、定位右侧栏,结合js滚动进行多图截取

5、使用PIL库进行多图拼接

注:本教程为示列代码,业务代码为方便阅读未进行封装,相关代码都进行了注释。

# -*- coding: utf-8 -*-
"""
@Time : 2023/6/25 14:50
@Email : Lvan826199@163.com
@公众号 : 梦无矶的测试开发之路
@File : PW_001_截图.py
"""
__author__ = "梦无矶小仔"

import time

from playwright.sync_api import sync_playwright, BrowserContext, Page
from PIL import Image


def switch_to_page(context: BrowserContext, url: str = None, title: str = None) -> Page:
    """
    切换到指定url
    :param context:传入一个浏览器上下文
    :param title: 当前标签页的标题
    :param url: 当前标签页的url
    :return: label_page:Page对象 返回对应的标签页,如果没找到则返回最新的标签页
    """
    for label_page in context.pages:
        if url:
            if url in label_page.url:
                label_page.bring_to_front()
                return label_page
        elif title:
            if title in label_page.title():
                label_page.bring_to_front()
                return label_page
    else:
        if title:
            print(f"没有找到【{title}】标题的标签页")
        if url:
            print(f"没有找到【{url}】网址的标签页")
    return context.pages[-1]


# 拼接图片的代码
def images_stitch(imgPath_1: str, imgPath_2: str, newImgPath: str) -> str:
    """
    :param imgPath_1: 第一张图片的路径,
    :param imgPath_2: 第二张图片的路径,
    :param newImgPath: 拼接图片的路径,
    :return: newImgPath
    """
    # 获取JPG、png图像的路径
    im_list_1 = [imgPath_1, imgPath_2]
    im_list = [Image.open(fn) for fn in im_list_1]
    # 图片转化为相同的尺寸
    ims = []
    for i in im_list:
        new_img = i.resize((1920, 961), Image.BILINEAR)
        ims.append(new_img)
    # 单幅图像尺寸
    width, height = ims[0].size
    # 创建空白长图
    result = Image.new(ims[0].mode, (width, height * len(ims)))
    # 拼接图片
    for i, im in enumerate(ims):
        result.paste(im, box=(0, i * height))
    # 保存图片
    result.save(newImgPath)
    return newImgPath

# 主代码

playwright = sync_playwright().start()
# 连接已经打开的浏览器,找好端口
browser = playwright.chromium.connect_over_cdp("http://127.0.0.1:9223")
default_context = browser.contexts[0]
print(type(default_context))
page = default_context.pages[0]

projectID = 6691166666666666666
gameID = 497566666666666666
timeRange = 7

# 官方教程 https://playwright.dev/python/docs/api/class-page#page-evaluate

url123 = f'https://play.google.com/console/u/0/developers/{projectID}/app/{gameID}/vitals/metrics/overview?days={timeRange}'

page.evaluate(
    f'window.open("https://play.google.com/console/u/0/developers/{projectID}/app/{gameID}/vitals/metrics/overview?days={timeRange}", "_blank");'
)  # 执行js代码

page.wait_for_timeout(5000)

page = switch_to_page(default_context, url123)

### 进行截图
# 官方教程 https://playwright.dev/python/docs/screenshots#full-page-screenshots
now_time = time.time_ns()
page.wait_for_timeout(1000)
page.locator("#main-content").click()
page.wait_for_timeout(1000)

image_path_1 = f'./img-{now_time}.png'
page.locator("#main-content").screenshot(path=f'img-{now_time}.png')
print("截图成功001")

page.wait_for_timeout(1000)
js = 'document.getElementById("main-content").scrollTo(600,800)'
# page.evaluate_handle(js)
page.evaluate(js)
print("执行了js滚动")
page.wait_for_timeout(1000)
now_time = time.time_ns()
image_path_2 = f'./img-{now_time}.png'
page.locator("#main-content").screenshot(path=f'img-{now_time}.png')
print("截图成功002")

# 截图拼接
new_image_path = './image_result.png'
result_img_path = images_stitch(image_path_1,image_path_2,new_image_path)
print(f"完整长截图路径:{result_img_path}")

最终长截图效果展示

在这里插入图片描述

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

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

相关文章

JetBrains设置文件名格式

如题,在使用CLion创建C类时,希望创建的文件名符合Google编码规范。设置如下图所示: 创建的C类是PascalCase格式,对应的文件名是pascal-case格式。

例举onekey一键还原如何使用

onekey一键还原怎么使用呢​​​​​​​?随着数字化的发展,现在电脑已成为人们工作学习娱乐的必备工具,想要放心的使用电脑,不仅需要杀毒软件,还需要一款一键还原软件。接下来,我就教大家如何使用onekey一键还原。还…

word文档如何引用参考文献

参考 word文档如何引用参考文献 说明

华南理工大学811信号与系统考研分数线,招生人数,报考统计,考情分析,就业,真题,大纲,参考书,华工811

华南理工大学811信号与系统考研分数线,招生人数,报考统计,考情分析,就业,真题,大纲,参考书,华工811 华南理工大学811信号与系统考研分数线,招生人数,报考统…

数据结构:线性表(栈的实现)

文章目录 1. 栈(Stack)1.1 栈的概念1.2 栈的结构链表栈数组栈 2. 栈的定义3. 栈的实现3.1 初始化栈 (StackInit)3.2 入栈 (StackPush)3.3 出栈 (StackPop)3.4 检测栈是否为空 (StackEmpty)3.5 获取栈顶元素 (StackTop)3.6 获取栈中有效元素个数 (StackSize)3.7 销毁栈 (StackDe…

Unity Animation、Animator 的使用

文章目录 1. 添加动画2. Animation2.1 制作界面2.2 制作好的 Animation 动画2.3 添加和使用事件 3. Animator3.1 制作界面3.2 一些参数解释3.3 动画参数 4. Animator中相关类、属性、API4.1 类4.2 属性4.3 API4.4 几个关键方法 5. 动画播放和暂停控制 1. 添加动画 选中待提添加…

2023 INCLUSION·外滩大会丨拓数派科技战略深度披露,大模型数据计算系统蓄势待发

近日,被亿欧网誉为最值得关注的全球化大模型数据计算科技新锐拓数派亮相在黄浦区世博园举行的2023 INCLUSION外滩大会。作为国际顶尖的科技盛会,来自全球各地的著名经济学家、诺奖得主、企业家和技术大咖们济济一堂,围绕“科技创造可持续未来…

聚观早报|小米14渲染图曝光;蚂蚁金融大模型正式发布

【聚观365】9月9日消息 小米14渲染图曝光 蚂蚁金融大模型正式发布 路特斯推出全电动轿车Emeya 上汽集团8月整车销量42.3万辆 ChatGPT网站流量连续三个月下滑 小米14渲染图曝光 高通旗下全新一代旗舰芯片骁龙8 Gen3将于10月24-26日举办的骁龙技术峰会上亮相,相…

安装SAPGUI 8.0

SAP_GUI_for_Windows_8.00_Comp.64\PRES1\GUI\Windows\Win64

windows11安装docker时,修改默认安装到C盘

1、修改默认安装到C盘 2、如果之前安装过docker,请删除如下目录:C:\Program Files\Docker 3、在D盘新建目录:D:\Program Files\Docker 4、winr,以管理员权限运行cmd 5、在cmd中执行如下命令,建立软联接: m…

【Mysql】给查询记录增加序列号方法

在MySQL 8.0版本中,你可以使用ROW_NUMBER()函数来添加序号。以下是一个示例查询,演示如何添加序号: SELECT ROW_NUMBER() OVER (ORDER BY column_name) AS serial_number,column1, column2, ... FROMyour_table;请将column_name替换为你想要…

FPGA时序分析与约束(5)——时序路径

一、前言 在之前的文章中我们分别介绍了组合电路的时序,时序电路的时序和时钟的时序问题,我们也对于时序分析,时序约束和时序收敛几个基本概念进行了区分,在这篇文章中,我们将介绍时序约束相关的最后一部分基本概念&am…

【网络知识点】三次握手和四次挥手

文章目录 一、三次握手二、四次挥手 一、三次握手 三次握手的原理如下: 客户端向服务器发送一个SYN(同步)包,其中包含一个随机生成的初始序列号(ISN)。 服务器收到SYN包后,会发送一个SYNACK&…

SpringBoot配置文件加载顺序

Spring Boot 启动时,会自动加载 JAR 包内部及 JAR 包所在目录指定位置的配置文件(Properties 文件、YAML 文件),下图中展示了 Spring Boot 自动加载的配置文件的位置及其加载顺序,同一位置下,Properties 文…

np.where 和 np.argwhere的区别

np.where 和 np.argwhere 都是NumPy库中用于条件查找的函数,但它们有一些重要的区别: 返回类型: np.where 返回满足条件的元素的坐标作为元组。如果是多维数组,返回的是两个分别包含满足条件的行坐标和列坐标的数组(或多维坐标&am…

USB Server应用于汇丰晋信基金

为了满足UKey远程连接调用、安全集群管理需求,汇丰晋信基金选择了朝天椒USB Server作为其解决方案。朝天椒USB Server以其卓越的性能和可靠性,为汇丰晋信基金提供了稳定的Ukey连接管理服务。这一选择不仅提高了汇丰晋信基金的工作效率,还保障…

第三方服务提权

nfs挂载原理 目标机器192.168.17.138 开启2049 nfs端口 查看目标开放的文件夹 showmount -e 192.168.17.138 回显:/home/peter * 说明可挂载/home/peter的所有目录 使用WinSCP链接靶机192.168.17.138 更改名字为 authorized_keys 靶机 赋值权限 攻击机 nfs挂载提…

idea配置git(gitee)并提交(commit)推送(push)

Intellij Idea VCS | 版本控制 - 知乎 IDEA项目上传到gitee仓库_idea上传代码到gitee_robin19712的博客-CSDN博客 git程序下载国内镜像地址: https://registry.npmmirror.com/binary.html?pathgit-for-windows/v2.42.0.windows.2/ 解压后放到固定路径&#xff1a…

Python,Bytetrack ,lap.lapjv,匈牙利匹配

lap.lapjv貌似是一个比匈牙利算法快的算法。 函数的参数: 如果是非方阵,extend_cost需要是True。 cost_limit,小于等于这个数值的分配代价才会分配。 def lapjv(*args, **kwargs): # real signature unknown"""Solve linear a…

彻底掌握Protobuf编码原理与实战

目录 1.类型2.VARINT 2.1 无符号数2.2 有符号数3.定长 3.1 I64类型3.2 I32类型4.LEN5.代码 学习这些有什么用? - 如果你是后端开发者,掌握这个对工作非常有用 - 如果你是求职者,面试时可以临危不惧 1.类型 最近看到有直接操作wire type相关的…