作者声明:
本程序并不鼓励各位读者违反京东平台的使用条款及相关法律规定!本文章仅作为学习交流和提供思路使用! 相关重要程序已对部分代码进行模糊处理!
import time import base64 import re from io import BytesIO import cv2 from selenium import webdriver from selenium.webdriver.chrome.service import Service from selenium.webdriver.common.by import By import os import numpy as np from PIL import Image import matplotlib.pyplot as plt
一、保存滑块和背景图
实际上获取这两个图片一点都不复杂甚至可以说是非常简单,只需要会一点点爬虫:
只需要提取到src标签,然后解码即可:
small_img = driver.find_element(By.CSS_SELECTOR, '.JDJRV-img-panel .JDJRV-smallimg img ') small_img_src = small_img.get_attribute("src") base64_str_small = re.sub(r'^data:image/.+;base64,', '', small_img_src) # 使用小图的解码数据 image_data_small = base64.b64decode(base64_str_small) # 创建小图对象 image_small = Image.open(BytesIO(image_data_small))
二、分析滑块提取轮廓
# 加载滑块图 img_path = "你的滑块图路径" img = cv2.imread(img_path) # 转换为灰度图像 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 假设我们选择 100 到 200 之间的灰度值 lower_gray = 100 upper_gray = 200 # 创建二值化掩码,只保留指定范围内的灰度 mask = cv2.inRange(gray, lower_gray, upper_gray) # 找到轮廓 contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 创建一个副本用于绘制 img_with_contours = img.copy() # 绘制轮廓 for contour in contours: # 用绿色线条绘制 cv2.drawContours(img_with_contours, [contour], -1, (0, 255, 0), 1) # 找到最大的轮廓,并计算其外接矩形 if contours: max_contour = max(contours, key=cv2.contourArea) # 获得外接矩形 x, y, w, h = cv2.boundingRect(max_contour) # 用绿色矩形标记 cv2.rectangle(img_with_contours, (x, y), (x + w, y + h), (0, 255, 0), 2)
三、获取滑动块在背景图上的位置信息
element =driver.find_element(By.CSS_SELECTOR,'.JDValidate-wrap .JDJRV-img-panel .JDJRV-smallimg ') # 获取 style 属性 style_value = element.get_attribute("style") # 解析 style 属性中的 top 和 width top_value_str = re.search(r'top:\s*([0-9.]+)px', style_value).group(1) width_value_str = re.search(r'width:\s*([0-9.]+)px', style_value).group(1) # 转换为数值 top_value = float(top_value_str) width_value = float(width_value_str) # 计算滑块的上下边界 # 滑块的顶部位置 slider_top = top_value # 滑块的高度(根据 width 推断) slider_height = width_value # 滑块的底部位置 slider_bottom = slider_top + slider_height print("Top value:", slider_top) print("Bottom value:", slider_bottom)
四、裁剪干扰部分并匹配颜色和轮廓
# 获取背景图 big_img = driver.find_element(By.CSS_SELECTOR, '.JDJRV-img-panel .JDJRV-bigimg img ') big_img_src = big_img.get_attribute("src") # 处理 Base64 数据 base64_str_big = re.sub(r'^data:image/.+;base64,', '', big_img_src) image_data_big = base64.b64decode(base64_str_big) image_big = Image.open(BytesIO(image_data_big)) # 创建存储目录 output_dir = "images" os.makedirs(output_dir, exist_ok=True) # 将背景图转换为 OpenCV 格式 background_img = cv2.cvtColor(np.array(image_big), cv2.COLOR_RGB2BGR) # 调整背景图尺寸为 242x94 resized_background_img = cv2.resize(background_img, (242, 94)) # 裁剪背景图 crop_margin = 36 y1 = int(slider_top ) y2 = int(slider_bottom ) cropped_background = resized_background_img[y1:y2, crop_margin:-crop_margin] # 首先计算每个像素的 RGB 平均值 mean_rgb = np.mean(cropped_background, axis=2) # 计算每个像素的 RGB 平均值 # 创建掩码,确保平均值大于等于10,小于等于90 mask = (mean_rgb >= 10) & (mean_rgb <= 90) # 符合条件的布尔掩码 mask = mask.astype(np.uint8) * 255 # 转换为二值掩码 (0 和 255) # 提取轮廓 contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 获取滑动块图像 slider_img_path = os.path.join(output_dir, "huaKuai_image.png") slider_img = cv2.imread(slider_img_path) # 转换为灰度并二值化 gray_slider = cv2.cvtColor(slider_img, cv2.COLOR_BGR2GRAY) _, binary_slider = cv2.threshold(gray_slider, 100, 200, cv2.THRESH_BINARY) slider_contours, _ = cv2.findContours(binary_slider, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) slider_contour = max(slider_contours, key=cv2.contourArea) # 最少尝试5次 max_attempts = 5 attempt = 0 best_match = None lowest_diff = float("inf") while attempt < max_attempts: for contour in contours: similarity = cv2.matchShapes(slider_contour, contour, cv2.CONTOURS_MATCH_I1, 0) if similarity < lowest_diff: area = cv2.contourArea(contour) # 检查面积在 400 到 1500 之间 if 400 < area < 1400: best_match = contour lowest_diff = similarity break attempt += 1 if best_match is not None: break if best_match is not None: x, y, w, h = cv2.boundingRect(best_match) cv2.rectangle(cropped_background, (x, y), (x + w, y + h), (0, 255, 0), 2) the_distance=x+36 # 保存图像 output_path = os.path.join(output_dir, "matched_image.png") cv2.imwrite(output_path, cropped_background) # 显示结果 plt.imshow(cv2.cvtColor(cropped_background, cv2.COLOR_BGR2RGB)) plt.title("Best Match with Area Check") plt.axis("off") plt.show() else: print("未找到满足条件的轮廓") do_actionchains(driver, the_distance)
五、拖动滑块实现登录
这里不做演示,尽量模拟人类拖动验证码的习惯,否则即使完全重合也会登陆失败!