Python3网络爬虫开发实战(8)验证码的识别

news2024/11/14 1:14:55

文章目录

  • 一、 图片增强:OpenCV
    • 1. OpenCV 基础使用
    • 2. 滑动验证码缺口识别
  • 二、图片验证码和滑块验证码
    • 1. tesserocr
    • 2. ddddocr
    • 3. 深度学习识别
    • 4. 超级鹰打码平台
  • 三、手机验证码的自动化处理

目前,许多网站采取各种各样的措施来反爬虫,其中一个措施便是使用验证码。随着技术的发展,验证码的花样越来越多。验证码最初是几个数字组合的简单的图形验证码,后来加入了英文字母和混淆曲线。有的网站还可能看到中文字符的验证码,这使得识别愈发困难。

一、 图片增强:OpenCV

1. OpenCV 基础使用

文中使用 Opencv 来识别目标缺口位置,Opencv 是一个计算机视觉和算法库,其安装也十分简单;

pip install python-opencv

高斯滤波

import cv2

blur_image = cv2.GaussianBlur(src, ksize, sigmaX, sigmaY, borderType)
  • src 输入图像,可以是单通道灰度图像或多通道彩色图像
  • ksize 高斯核的大小,是一个 (width, height) 的元组,必须是正数和奇数
  • sigmaX X 轴方向上的高斯核的标准差
  • dst 输出图像,如果未指定,将创建与 src 相同大小和类型的图像
  • sigmaY Y 轴方向上的高斯核的标准差,如果为 0,则 sigmaY 将与 sigmaX 相同
  • borderType 边界处理方式,默认为 cv2.BORDER_DEFAULT
  • blur_image 表示

边缘检测

import cv2

edges = cv.Canny(image, threshold1, threshold2[, apertureSize[, L2gradient]])
  • edges 为计算得到的边缘图像
  • image 为 8 位输入图像
  • threshold1 表示处理过程中的第一个阈值
  • threshold2 表示处理过程中的第二个阈值
  • apertureSize 表示 Sobel 算子的孔径大小
  • L2gradient 为计算图像梯度幅度(gradient magnitude)的标识。其默认值为 False。如果为 True,则使用更精确的 L2 范数进行计算(即两个方向的导数的平方和再开方),否则使用 L1 范数(直接将两个方向导数的绝对值相加)

轮廓提取

import cv2

contours, hierarchy = cv2.findContours(image,mode,method)
  • image:二值图,即黑白的(不是灰度图),所以读取的图像要先转成灰度的,再转成二值图。
  • mode:轮廓的模式。cv2.RETR_EXTERNAL只检测外轮廓;cv2.RETR_LIST检测的轮廓不建立等级关系;cv2.RETR_CCOMP建立两个等级的轮廓,上一层为外边界,内层为内孔的边界。如果内孔内还有连通物体,则这个物体的边界也在顶层;cv2.RETR_TREE建立一个等级树结构的轮廓。
  • method:轮廓的近似方法。cv2.CHAIN_APPROX_NOME存储所有的轮廓点,相邻的两个点的像素位置差不超过1;cv2.CHAIN_APPROX_SIMPLE压缩水平方向、垂直方向、对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需要4个点来保存轮廓信息;cv2.CHAIN_APPROX_TC89_L1,cv2.CV_CHAIN_APPROX_TC89_KCOS
  • contours:返回的轮廓
  • hierarchy:每条轮廓对应的属性

外接矩形

import cv2

retval = cv2.boundingRect(array)
  • retval 表示返回矩形边界左上角顶点的坐标值及矩形边界的宽和高;
  • array 是灰度图像或轮廓;

轮廓面积

import cv2

area = cv2.contourArea(contour, oriented=None)
  • contour: 轮廓信息;
  • oriented: 方向标识符,默认值为 False,若取 True,则该方法会返回一个带符号的面积值,正负取决于轮廓的方向,若取 False,则面积值以绝对值的形式返回;
  • area: 轮廓的面积;

轮廓周长

import cv2

length = cv2.arclength(curve, closed)
  • curve: 轮廓信息
  • closed: 轮廓是否关闭
  • length: 轮廓的周长

2. 滑动验证码缺口识别

要实现这一流程,关键有两步:

  1. 识别目标缺口的位置;
  2. 将滑块拖到缺口的位置;

其中第二步的实现方式有很多,例如可以用 Selenium 等自动化工具模拟这个流程,验证并登入成功后获取对应的 Cookie 或者 Token 信息;也可以直接逆向验证码背后的 Javascript 逻辑,将缺口信息直接传给 Javascript 代码,执行获取类似于 密匙 信息的操作,再利用密匙进行下一步操作;

在这里我们可以利用 OpenCV 去识别目标缺口的位置,在这里我们首先定义高斯滤波,边缘检测,轮廓提取三个方法:

import cv2

GAUSSIAN_BLUR_KERNEL_SIZE = (5, 5)
GAUSSIAN_BLUR_SIGMA_X = 0
CANNY_THRESHOLD1 = 200
CANNY_THRESHOLD2 = 450

def get_gaussian_blur_image(image):
	'''传入待处理图片的信息,返回高斯滤波处理后的图片信息'''
	return cv2.GaussianBlur(image, GAUSSIAN_BLUR_KERNEL_SIZE, GAUSSIAN_BLUR_SIGMA_X)

def get_canny_image(image):
	'''传入待处理图片的信息,返回边缘检测处理后的图片信息'''
	return cv2.Canny(image, CANNY_THRESHOLD1, CANNY_THRESHOLD2)

def get_contours(image):
	'''传入待处理的图片信息,返回提取得到的轮廓信息'''
	contours, _ = cv2.findContours(image, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
	return contours

图片经过 高斯滤波,边缘检测,轮廓提取 这三个方法后,得到各个轮廓的信息,我们需要根据这些轮廓的外接矩形的面积和周长筛选想要的结果,

在这里我们可以给面积,周长和缺口位置都设定一个范围,经过实际测量可以得出目标缺口的外接矩形的高度大约是验证码高度的 0.25 倍,宽度大约是验证码宽度的 0.15 倍,所以在允许误差是 20% 的情况下,可以根据验证码的宽高信息大约计算出外接矩形的面积和周长的取值范围。同时缺口的位置有一个最小偏移量和最大偏移量,这里最小偏移量是验证码宽度的 0.2 倍,最大偏移量是验证码宽度的 0.85 倍,将这些综合起来我们可以定义三个阈值方法:

def get_contour_area_threshold(image_width, image_height):
	'''定义目标轮廓的面积下限和上限'''
	contour_area_min = (image_width * 0.15) * (image_height * 0.25) * 0.8
	contour_area_max = (image_width * 0.15) * (image_height * 0.25) * 1.2
	return contour_area_min, contour_area_max

def get_arc_length_threshold(image_width, image_height):
	'''定义目标轮廓的周长下限和上限'''
	arc_length_min = ((image_width * 0.15) + (image_height * 0.25)) * 2 * 0.8
	arc_length_max = ((image_width * 0.15) + (image_height * 0.25)) * 2 * 1.2
	return arc_length_min, arc_length_max

def get_offset_threshold(image_width):
	'''定义缺口位置的偏移量下限和上限'''
	offset_min = 0.2 * image_width
	offset_max = 0.85 * image_width
	return offset_min, offset_max

定义完毕后,我们只需要遍历各个轮廓的信息,然后根据这三个上下限进行筛选;

# 获得轮廓信息
image_raw = cv2.imread('captcha.png')
image_height, image_width, _ = image_raw.shape
image_gaussian_blur = get_gaussian_blur_image(image_raw)
image_canny = get_canny_image(image_gaussian_blur)
contours = get_contours(image_canny)

# 获得上下限
contour_area_min, contour_area_max = get_contour_area_threshold(image_width, image_height)
arc_length_min, arc_length_max = get_arc_length_threshold(image_width, image_height)
offset_min, offset_max = get_offset_threshold(image_width)

# 筛选信息
offset = None
for contour in contours:
	x, y, w, h = cv2.boundingRect(contour)
	if contour_area_min < cv2.contourArea(contour) < contour_area_max and
		arc_length_min < cv2.arcLength(contour, True) < arc_length_max and
		offset_min < x < offset_max:
		cv2.rectangle(image_raw, (x, y), (x + w, y + h), (0, 0, 255), 2)
		offset = x

cv2.imwrite('image_label.png', image_raw)
print('offset:', offset)

得到缺口信息后,我们可以使用 Selenium 等自动化工具模拟这个流程,验证并登入成功后获取对应的 Cookie 或者 Token 信息;也可以直接逆向验证码背后的 Javascript 逻辑,将缺口信息直接传给 Javascript 代码,执行获取类似于 密匙 信息的操作,再利用密匙进行下一步操作;

二、图片验证码和滑块验证码

图片验证码基本上都是使用 OCR 来解决的,这里有几种方法;

1. tesserocr

tesserocr 是 Python 的一个 OCR 识别库 ,但其实是对 tesseract 做的一 层 Python API 封装,所以它的核心是 tesseract。 因此,在安装 tesserocr 之前,我们需要先安装tesseract。

进入网站:Index of /tesseract (uni-mannheim.de),寻找 tesseract-ocr-w64-setup-v***.exe,下载完毕后安装,找到安装路径,将路径添加到环境变量中;这样 tesseract 就安装完毕了,接下来安装 tesserocr;

pip install tesserocr

识别图片

import tesserocr
from PIL import Image

# mode:1
image = Image.open('code.jpg')
result = tesserocr.image_to_text(image)

# mode:2
result = tesserocr.file_to_text('code.jpg')

print(result)

针对一些有干扰的图片,我们做一些灰度和二值化处理,这会提高图片识别的正确率。

但是在这里咱们不推荐使用 tesserocr,主要有两个缺点:1. 识别准确率低;2. 安装起来麻烦;

2. ddddocr

国产开发的一个验证码识别库,DdddOcr、最简依赖的理念,尽量减少用户的配置和使用成本,希望给每一位测试者带来舒适的体验:sml2h3/ddddocr: 带带弟弟 通用验证码识别OCR pypi版 (github.com)

安装 ddddocr 相当简单,直接 pip 安装就好;

pip install ddddocr

ddddocr 有许多的功能,如基础的 ocr 识别能力可以识别图片验证码:主要用于识别单行文字,即文字部分占据图片的主体部分,例如常见的英数验证码等,本项目可以对中文、英文(随机大小写or通过设置结果范围圈定大小写)、数字以及部分特殊字符。

import ddddocr

ocr = ddddocr.DdddOcr()

image = open("example.jpg", "rb").read()
result = ocr.classification(image)
print(result)

本库内置有两套ocr模型,默认情况下不会自动切换,需要在初始化ddddocr的时候通过参数进行切换

import ddddocr

ocr = ddddocr.DdddOcr(beta=True)  # 切换为第二套ocr模型

image = open("example.jpg", "rb").read()
result = ocr.classification(image)
print(result)

提示 对于部分透明黑色png格式图片得识别支持: classification 方法 使用 png_fix 参数,默认为False

 ocr.classification(image, png_fix=True)

目标检测能力可以识别图片中的点击位置:主要用于快速检测出图像中可能的目标主体位置,由于被检测出的目标不一定为文字,所以本功能仅提供目标的bbox位置 (在⽬标检测⾥,我们通常使⽤bbox(bounding box,缩写是 bbox)来描述⽬标位置。bbox是⼀个矩形框,可以由矩形左上⻆的 x 和 y 轴坐标与右下⻆的 x 和 y 轴坐标确定)

如果使用过程中无需调用ocr功能,可以在初始化时通过传参ocr=False关闭ocr功能,开启目标检测需要传入参数det=True

import ddddocr
import cv2

det = ddddocr.DdddOcr(det=True)

with open("test.jpg", 'rb') as f:
    image = f.read()

bboxes = det.detection(image)
print(bboxes)

im = cv2.imread("test.jpg")

for bbox in bboxes:
    x1, y1, x2, y2 = bbox
    im = cv2.rectangle(im, (x1, y1), (x2, y2), color=(0, 0, 255), thickness=2)

cv2.imwrite("result.jpg", im)

滑块检测能力,是基于 OpenCV 实现的:本项目的滑块检测功能并非AI识别实现,均为opencv内置算法实现。可能对于截图党用户没那么友好~,如果使用过程中无需调用ocr功能或目标检测功能,可以在初始化时通过传参ocr=False关闭ocr功能或det=False来关闭目标检测功能

其中有两种算法,第一种原理是通过滑块图像的边缘在背景图中计算找到相对应的坑位,可以分别获取到滑块图和背景图,滑块图为透明背景图

滑块图

背景图

det = ddddocr.DdddOcr(det=False, ocr=False)

with open('target.png', 'rb') as f:
	target_bytes = f.read()

with open('background.png', 'rb') as f:
	background_bytes = f.read()

res = det.slide_match(target_bytes, background_bytes)

print(res)

由于滑块图可能存在透明边框的问题,导致计算结果不一定准确,需要自行估算滑块图透明边框的宽度用于修正得出的bbox

提示:如果滑块无过多背景部分,则可以添加simple_target参数, 通常为jpg或者bmp格式的图片

slide = ddddocr.DdddOcr(det=False, ocr=False)

with open('target.jpg', 'rb') as f:
	target_bytes = f.read()

with open('background.jpg', 'rb') as f:
	background_bytes = f.read()

res = slide.slide_match(target_bytes, background_bytes, simple_target=True)

print(res)

第二种算法的原理是:通过比较两张图的不同之处进行判断滑块目标坑位的位置

参考图a,带有目标坑位阴影的全图

参考图b,全图

slide = ddddocr.DdddOcr(det=False, ocr=False)

with open('bg.jpg', 'rb') as f:
	target_bytes = f.read()

with open('fullpage.jpg', 'rb') as f:
	background_bytes = f.read()

img = cv2.imread("bg.jpg")

res = slide.slide_comparison(target_bytes, background_bytes)

print(res)

OCR概率输出,为了提供更灵活的ocr结果控制与范围限定:项目支持对ocr结果进行范围限定。

可以通过在调用classification方法的时候传参probability=True,此时classification方法将返回全字符表的概率 当然也可以通过set_ranges方法设置输出字符范围来限定返回的结果。

set_ranges 方法限定返回字符返回

本方法接受1个参数,如果输入为int类型为内置的字符集限制,string类型则为自定义的字符集

如果为int类型,请参考下表

参数值意义
0纯整数0-9
1纯小写英文a-z
2纯大写英文A-Z
3小写英文a-z + 大写英文A-Z
4小写英文a-z + 整数0-9
5大写英文A-Z + 整数0-9
6小写英文a-z + 大写英文A-Z + 整数0-9
7默认字符库 - 小写英文a-z - 大写英文A-Z - 整数0-9

如果为string类型请传入一段不包含空格的文本,其中的每个字符均为一个待选词 如:"0123456789+-x/=""

import ddddocr

ocr = ddddocr.DdddOcr()

image = open("test.jpg", "rb").read()
ocr.set_ranges("0123456789+-x/=")
result = ocr.classification(image, probability=True)
s = ""
for i in result['probability']:
    s += result['charsets'][i.index(max(i))]

print(s)

最后该项目的 AI 模型支持自定义OCR训练模型导入:本项目支持导入来自于 dddd_trainer 进行自定义训练后的模型,参考导入代码为

import ddddocr

ocr = ddddocr.DdddOcr(det=False, ocr=False, import_onnx_path="myproject_0.984375_139_13000_2022-02-26-15-34-13.onnx", charsets_path="charsets.json")

with open('test.jpg', 'rb') as f:
    image_bytes = f.read()

res = ocr.classification(image_bytes)
print(res)

3. 深度学习识别

简单的图片验证码识别可以使用深度学习中的 Faster R-CNN 和 LSTM 来执行:Python深度学习基于Tensorflow(15)OCR验证码 文本检测与识别实例_tensorflow 文字识别-CSDN博客

滑动验证码的缺口,也可以使用深度学习来识别,其任务具体来说就是一个单纯的目标检测任务,目前比较流行的目标检测算法有 R-CNN,Fast R-CNN,Faster R-CNN,SSD,YOLO 等;

其中目标检测算法分为两类,一类是一阶段目标检测,具有代表性的是 SSD 和 YOLO;另一类是二阶段目标检测,具有代表性的是 R-CNN,Fast R-CNN,Faster R-CNN。前者检测速度较快,但是准确性较低(对比);

滑动验证码缺口的识别模型具体操作方式是利用多次请求滑动验证码网站获取滑块图像,然后利用 LabelImg 工具将收集到的滑动验证码图像缺口框起来,放入目标检测模型中训练,利用训练好的模型对新的验证码进行缺口识别;

4. 超级鹰打码平台

利用打码平台可以轻松的识别各种各样的验证码,图形验证码,滑动验证码,点选验证码和逻辑验证码等等,而且不需要懂任何算法,只需要向 API 上传验证码图片,它便会返回对应的识别结果;

API 接口 demo 测试如下:Python语言Demo下载-超级鹰验证码识别API接口 (chaojiying.com)

三、手机验证码的自动化处理

现在许多的验证码需要提供手机号码发送短信验证码来验证,我们需要将手机上的短信验证码发送到 PC 端上,然后利用发送请求;

对于安卓手机,这里有两种方式,第一种是使用安卓开发的方式;第二种是使用一个开源软件 SmsForwarder,中文叫做短信转发器;pppscn/SmsForwarder: 短信转发器——监控Android手机短信、来电、APP通知,并根据指定规则转发到其他手机:钉钉群自定义机器人、钉钉企业内机器人、企业微信群机器人、飞书机器人、企业微信应用消息、邮箱、bark、webhook、Telegram机器人、Server酱、PushPlus、手机短信等。包括主动控制服务端与客户端,让你轻松远程发短信、查短信、查通话、查话簿、查电量等。(V3.0 新增)PS.这个APK主要是学习与自用,如有BUG请提ISSUE,同时欢迎大家提PR指正 (github.com)

除此之外,我们还可以使用专业的手机卡池和猫池配以专业的软件设备实现短信监听;

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

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

相关文章

嵌入式面经篇四——内存管理

文章目录 前言一、内存管理&编程题1、由gcc编译的C语言程序占用的内存分为哪几个部分&#xff1f;2、大小端3、全局变量和局部变量的区别&#xff1f;4、以下程序中&#xff0c;主函数能否成功申请到内存空间&#xff1f;5、请问运行下面的 Test() 函数会有什么样的后果&am…

Anaconda安装jupyter notebook、jupyterlab及体验

Anaconda安装jupyter 1.前言2.创建虚拟环境3.激活虚拟环境4.安装jupyter notebook5.启动6.快捷方式7.jupyterlab插件安装8.报错的处理9.总结1.前言 手贱,不小心将Anaconda自带得jupyter给卸载了,没法子了查了好多资料都比较麻烦,所以自己摸索着重新安装,记录一下心得。 说…

87.SAP Transaction SM31 and SM30

目录 1.SM30是什么 2.SM30维护表的前提条件&#xff1a; 3.用途 维护表数据 查看SAP表的配置点 4.SM31和SM30的区别 1.SM30是什么 Transaction code SM30 can be used to display and update table data. The input field on the first screen of SM30 is long enough t…

企业通用报表平台代码审计

1 第三方组件漏洞审计 本项目是基于Maven构建的。对于Maven项目,我们首先从 pom.xml 文件开始审计引入的第三方组件是 否存在漏洞版本,然后进一步验证该组件是否存在漏洞点。 本项目引入的组件以及组件版本整理如下。 组件名称组件版本SpringBoot2.2.4.RELEASEFastjson1.2…

CDP问卷填报手册指南

CDP认证的作用是向消费者和利益相关者提供一个可信的证明&#xff0c;证明该组织正在采取行动&#xff0c;以减少其对气候变化的影响并提高可持续发展。CDP认证是一个独立的评估过程&#xff0c;通过评估组织在应对气候变化和可持续发展方面的表现和策略&#xff0c;评估其对气…

免费下载专利

给大家提供一个可以免费下载专利的地方 链接&#xff1a;https://www.drugfuture.com/cnpat/cn_patent.asp

玩转生产环境全链路压测

一、什么是生产环境全链路压测 生产环境全链路压力测试&#xff08;Production Environment Full-Link Stress Testing&#xff09;是一种针对线上系统进行的综合性性能测试方法。这个过程涉及模拟实际用户行为&#xff0c;从用户界面到后端数据库的整个应用链路上施加预定的高…

考拉悠然完成自研国内首台玻璃基Micro LED晶圆量检测设备出货

近日&#xff0c;考拉悠然自主研发的国内首台玻璃基Micro LED晶圆量检测设备正式完成出货&#xff0c;这不仅标志着考拉悠然在Micro LED核心检测技术上的重大突破&#xff0c;也展现了公司在高端制造领域的技术创新能力。 Micro LED显示技术被认为是未来的“终极显示技术”&am…

stm32—GPIO

0. 引入 在单片机产品中,我们常常可以见到三种模块:LCD灯、KEY按键、BEEP蜂鸣器 LED灯: 一个比较常见的LED电路LED0 ---------- 通过控制LED0引脚(电线) 给它一个低电平(低电压),LED灯就会亮 给它一个高电平(高电压),LED灯就会灭 …

Spring——AOP前言(写一个小demo为了好学习AOP)

1.AOP的概念 1.1 AOP简单样例 我们来先通过一个例子来对AOP进行理解&#xff0c;这个例子就是有关Spring的事务的一个样例&#xff0c;有关Spring是怎么实现事务的&#xff0c;这个事务其实本质上就是对于我们代码的一个增强。废话不多说&#xff0c;上程序&#xff0c;请各位…

【Datawhale AI夏令营第四期】魔搭-AIGC方向 Task02笔记 Scepter工具箱, 精读BaseLine代码

【Datawhale AI夏令营第四期】魔搭-AIGC方向 Task02笔记 Task02学习任务&#xff1a; https://linklearner.com/activity/14/10/32 传送门 我们继续看网课&#xff0c;并且在Kimi.AI的帮助下读一下BaseLine示例代码。 网课链接&#xff1a;https://space.bilibili.com/1069874…

如何创建一个SpringBoot项目呢?SpringBoot有什么优点呢?

目录 一、SpringBoot的优点 二、SpringBoot项目的创建 &#xff08;一&#xff09;通过Idea创建 &#xff08;二&#xff09;通过网页来创建Spring Boot项目 三、SpringBoot的目录 拓展知识 Spring的诞生是为了简化Java代码的开发&#xff0c;而Spring Boot的诞生是为了简…

剪映怎么剪辑视频?2024年剪辑软件精选!

在短视频风靡的时代&#xff0c;越来越多的人开始尝试自己制作短视频。而剪辑视频是短视频制作过程中至关重要的一环。很多小伙伴问剪映怎么剪辑视频&#xff1f;其实除了剪映&#xff0c;市面上还有不少剪辑软件操作简便&#xff0c;值得推荐&#xff01; 福昕视频剪辑 链接…

Dubbo源码深度解析(四)

接上篇博客《Dubbo源码深度解析(三)》&#xff0c;上篇博文&#xff0c;主要讲的是DubboBootstrap#start()方法中调用到的其他方法&#xff0c;以及讲到ServiceConfig#export()方法的调用链路。其中讲到最核心的方法为ServiceConfig#doExportUrlsFor1Protocol()&#xff0c;还没…

LVS详细解析及其NAT模式与DR模式部署(理论+实验全方位指导)

目录 1. 集群 2. 分布式系统 3. 集群与分布式的比较 4.通俗的解释 集群 分布式系统 总结 LVS&#xff08;Linux Virtual Server&#xff09;简介 LVS专业术语 工作原理 LVS调度算法 静态调度算法 动态调度算法 ipvsadm脑图 NAT模式集群 LVS的配置 在LVS主机内打开…

数据结构之顺序表的实现

主要参考&#xff1a; 【王道考研】王道数据结构与算法详细笔记&#xff08;全&#xff09;_王道数据结构笔记-CSDN博客 顺序表的概念 顺序表&#xff1a;用顺序存储的方式实现线性表顺序存储。把逻辑上相邻的元素存储在物理位置上也相邻的存储单元中&#xff0c;元素之间的关系…

1Panel配置

1. 脚本安装 curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && sh quick_start.sh2. 配置镜像加速 在容器-> 配置中设置&#xff0c;否则安装软件会失败。 https://docker.211678.top https://docker.1panel.live …

面对复杂订单统计,如何用这款工具化整为零?

最近制作报表时遇到了个问题&#xff0c;怎么把整合到一起的订单统计数据拆分成一个个单独的订单统计报表呢&#xff1f;经过一段时间的探索后&#xff0c;我找到了一款完全免费的报表软件&#xff0c;能够解决这个问题&#xff0c;这款软件叫作山海鲸可视化&#xff0c;我会在…

python 已知x+y=8 求x*y*(x-y)的最大值

先用导数求解 已知xy8 求xy(x-y)的最大值 令y8-x 则 f(x)x⋅(8−x)⋅(x−(8−x))x⋅(8−x)⋅(2x−8) 导数方程为 f(x)-3x^2 24x - 32 求方程 − 3 x 2 24 x − 32 0 -3x^2 24x - 32 0 −3x224x−320 的根。 首先&#xff0c;我们可以尝试对方程进行因式分解。观察…

Maven系列(一):Maven下载安装配置【Maven使Java构建事半功倍】

前言 ​ 作为Java开发工程师&#xff0c;那么Maven现已成为不可或缺的一部分&#xff0c;从最开始的依赖管理到编译运行及打包&#xff0c;可以说使伴随了Java项目的整个生命周期。那么这篇文章&#xff0c;将带你去认识Maven以及Maven的下载、安装、配置等等。 1. 什么是Mav…