这里写目录标题
- 出现条件:
- 解决方案:
- 获取滑动的距离
- 滑动验证
本教程无任何意向,纯纯的技术娱乐
虽然小概率出现问题,加入重试机制后,基本没出现过问题
注意:这里获取的距离与实际的距离不相同,本人是1920*1020的,但是与web中的比例为0.78
实际的值为(x - 13) * 281 / 360 这里的 - 13 是为了做矩形的补偿在10-13之间
出现条件:
- 短时间内多次失败
- 异常环境情况
- 未知
解决方案:
通过保存滑动图片,将图片进行灰度化,然后进行二值化,将图片变成黑白,获取所有矩形,并进行过滤,然后进行补偿机制
获取滑动的距离
def getXYByImage(filename: str) -> tuple[int, int]:
"""
从滑动验证码中获取xy坐标
"""
# 读取显示原图
image = cv2.imread(filename)
cv2.imshow("Original Image", image)
# cv2.waitKey(0)
# V通道 灰度图
hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
_, _, v_channel = cv2.split(hsv_image)
cv2.imshow('V Channel', v_channel)
# cv2.waitKey(0)
avg_hsv = get_avg(hsv_image)
logger.info(f"平均灰度值为 {avg_hsv}")
# 二值化 取灰度范围
ret1, thres = cv2.threshold(v_channel, avg_hsv, 255, cv2.THRESH_BINARY_INV)
cv2.imshow('Thresh', thres)
# cv2.waitKey(0)
# 闭运算
kernel = np.ones((25, 25), np.uint8)
thres = cv2.morphologyEx(thres, cv2.MORPH_OPEN, kernel)
cv2.imshow('MORPH_OPEN', thres)
# cv2.waitKey(0)
# 找到所有的矩形
contours, _ = cv2.findContours(thres, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
xys = []
# 遍历所有的矩形并计算其坐标和面积,并在原图上绘制绿色边框
for i, contour in enumerate(contours):
# 获取矩形的边界矩形(可能不是严格意义上的矩形,但是边界矩形)
x, y, w, h = cv2.boundingRect(contour)
# 计算面积
area = w * h
# 在原图上绘制绿色边框(注意:需要将图像转换为BGR格式以便正确显示颜色)
cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 1)
# print(f"Rectangle {i + 1}: Coordinates: ({x}, {y}), Area: {area}")
xys.append((x, y, area))
cv2.imshow("Image with Rectangles", image)
# cv2.imwrite(filename + "_Rectangles_.png", image)
# 筛选最适合的矩形
for x, y, a in xys:
if 1000 <= a <= 1100:
return x, y
def get_avg(img: cv2.typing.MatLike):
"""获取平均灰度值"""
# 获取图像高度和宽度
height = img.shape[0]
width = img.shape[1]
h_images = []
# 图像平均灰度处理方法
for i in range(height):
for j in range(width):
# 灰度值为RGB三个分量的平均值
var = (int(img[i, j][0]) + int(img[i, j][1]) + int(img[i, j][2])) / 3
h_images.append(var)
max_prot = h_images[int(len(h_images) / 2):]
max_prot.remove(min(max_prot))
return sum(max_prot) / len(max_prot)
def save_base64_image(code, name=None):
""" 保存base64 编码"""
imagedata = base64.b64decode(code)
file_name = os.path.join(os.path.dirname(__file__), str(time.time()) if name is None else name) + ".png"
with open(file_name, "wb") as f:
f.write(imagedata)
f.close()
return file_name
滑动验证
def _login_un_lock(self, locator: Locator):
src = locator.locator(".JDJRV-bigimg > img").get_attribute("src")
image_base64 = src[src.index(",") + 1 :]
file_name = save_base64_image(image_base64)
xy = getXYByImage(file_name)
logger.info(f"x ,y 坐标为{xy}")
if xy is None:
self.page.reload()
os.remove(file_name)
return
x, y = xy
self.un_login_lock(int((x - 13) * 281 / 360), locator.locator(".JDJRV-slide-btn"))
os.remove(file_name)
def un_login_lock(self, distance: int, locator: Locator) -> None:
locator.blur()
box = locator.bounding_box()
tracks = get_track(distance)
x = int(box["x"] + box["width"] / 2)
y = int(box["y"] + box["height"] / 2)
locator.hover()
self.page.mouse.down()
self.page.mouse.move(x, y + random.randint(10, 20), steps=12)
for track in tracks:
self.page.mouse.move(track + x, y + random.randint(10, 20), steps=9)
x = x + track
self.page.wait_for_timeout(random.randint(10, 100))
self.page.mouse.up()
self.page.wait_for_timeout(random.randint(2200, 3200))