资讯动态

Selenium自动化测试图片滑块验证码:缺口识别与拖拽轨迹实战

发布时间:2026/10/20 17:44:24 来源:尧图企业网站定制
搞定Selenium自动化测试图片滑块验证码这件事值得我专门写一篇总结聊聊。先说我为什么对这个话题有发言权。过去一年多我一直在给一家做电商系统的公司维护自动化测试脚本业务后台有十几个关键流程在登录或关键操作前都挂了滑块验证码。一开始大家都觉得这只是个小障碍结果自动化脚本一跑起来就全部挂掉。前前后后折腾了两三周我试了各种奇奇怪怪的办法最终才把一套稳定跨过图片滑块验证码的方案跑通。这篇文章没有教科书理论全是我反复用真实项目磨出来的记录包括原理、代码、参数、踩坑以及最后成功率稳定在九成以上的完整实现。这里说的“搞定”不是去找某种黑科技而是在自动化测试这个合法场景里让Selenium驱动浏览器绕过或通过滑块验证码的交互校验。适合的人群很明确正在做Web自动化测试的测试开发工程师、爬虫开发以及需要批量处理正常业务校验的运维同学。如果你想搞明白滑块验证码背后的识别逻辑、拖拽行为模拟、图像处理细节这篇文章应该能帮你省下几天的摸索时间。1. 为什么滑块验证码会成为自动化路上的拦路虎1.1 验证码演进的必然逻辑验证码之所以存在本质上是产品方在用户和机器之间做区分。传统的字符验证码、算术验证码容易被OCR技术破解于是逐步演化出滑块、点选、无感等模式。滑块验证码能在当前这么普及是因为它同时占了两头对真人来说操作成本极低滑动一下即可对机器来说它把“识别”和“行为”两个维度绑在一起难度一下子提升了。我观察下来滑块验证码的防机器逻辑主要有三个层面图像识别层面滑块需要移动的距离藏在带缺口的背景图中。机器必须能从像素层面判断缺口位置这个不是简单读文字那么直接。行为模拟层面机器拖拽的轨迹和真人差异很大。真人的手指或鼠标从起滑到落点会有加速、减速、甚至轻微回弹的过程而直接瞬移或匀速直线拖动很容易被判定为高风险。环境指纹层面Selenium驱动的浏览器通常带有一系列特征比如window.navigator.webdriver属性、浏览器启动参数异常等。验证码后台会综合风险评分决定是否弹验证码或增加校验难度。这三者叠在一起直接一把梭式地调drag_and_drop或move_by_offset成功率极低。哪怕勉强通过了下一次验证码的图片缺口位置完全随机算法不够通用换个页面就废了。1.2 图片滑块验证码的几种具体形态在实际项目里我遇到过的滑块验证码大体上有这几种形态标准缺口滑块一张背景大图一个滑块拼图缺口与拼图形状一致。当前国内不少主流平台的登录页和风控场景都在用。旋转角度滑块把图片旋转到正确角度才能通过。这种需要处理的是角度计算比位置计算复杂一些。乱序拼图滑块背景图被切成若干块拖动一块到目标位置完成拼图。背景滑块变种滑块不是固定在最左侧而是随机位置。本文重点讲的方案是为最常见的“标准缺口滑块”设计的但方案里的图像识别和轨迹模拟思路迁移到其他变种上也只是改个距离计算源的问题。提示如果你想做成一个长期稳定维护的自动化测试方案不要把所有逻辑写死在某个业务函数里而是把“图像识别”和“拖拽行为”拆成独立模块不同页面复用同一套核心逻辑。我后面就是这个思路。2. 动手前要准备的工具与核心环境2.1 Selenium版本和浏览器驱动的坑我用的是Selenium 4.x配合Chrome浏览器。这里有个特别容易踩的版本坑Selenium 4和高版本Chrome之间如果驱动不匹配连浏览器都起不来。驱动版本要和浏览器主版本号保持一致比如Chrome 120就对应ChromeDriver 120.x.x。如果你在自动化测试时需要更隐蔽地绕过环境特征检测可以关注undetected-chromedriver这类方案它本质上是一个带补丁的ChromeDriver包装器用起来和普通Selenium几乎一致。我在项目里会基于它封装一个统一的driver获取函数这样即使页面风控强度变化也不需要到处改代码。2.2 图像处理库OpenCV和Pillow图像部分我用的是OpenCVcv2加PillowPIL。Pillow负责从网页上抓取、保存图片OpenCV负责暴力但高效的像素计算。图像识别是整个方案的核心工具选型上基本没有争议OpenCV里常用的matchTemplate和Canny边缘检测两个接口已经足够应对大部分场景。安装可以直接用pippip install opencv-python pip install pillow pip install selenium2.3 自动化浏览器的基础封装在开始写识别逻辑之前我先做一个简单的启动函数。后面所有示例都依赖这个函数创建driverimport undetected_chromedriver as uc from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC def create_driver(): options uc.ChromeOptions() options.add_argument(--window-size1920,1080) # 禁用自动化提示条降低被检测概率 options.add_argument(--disable-blink-featuresAutomationControlled) # 根据自己实际的Chrome路径调整 driver uc.Chrome(optionsoptions, version_main120) driver.set_page_load_timeout(30) return driver这里有一个关键点值得多说一句--disable-blink-featuresAutomationControlled能去掉浏览器上“Chrome正在受到自动测试软件的控制”这个提示条同时会让navigator.webdriver属性不再直接暴露为true。虽然它不代表能隐藏所有指纹特征但作为自动化测试的基础配置能明显降低触发滑块验证码的概率。3. 核心攻防滑块位置与缺口识别3.1 定位网页元素与获取图片地址想计算滑动距离第一步是从页面结构里拿到元素和图片。我一般按下面的顺序来找到滑块手柄通常是某个带特定class的div。找到背景图可能是canvas、img或者一个带background-image样式的元素。拿滑块拼图有的页面会单独给一张小图有的只是背景图上的一个透明块。写代码的时候不要盲目用固定xpath因为不同业务的验证码DOM结构差异很大。我更推荐先用开发者工具手动分析一次然后针对特定页面写好定位函数。我这里用一个通用示例演示核心逻辑def get_slider_element(driver): # 滑块手柄一般有 slider 或 btn_slide 之类的标志 return WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.CSS_SELECTOR, div.slider)) ) def get_background_image(driver): # 背景图常见的有 bg-img 或背景URL形式 el driver.find_element(By.CSS_SELECTOR, div.bg-img) style el.get_attribute(style) import re url re.search(rurl\(?(.*?)?\), style).group(1) return url图片地址拿到后怎么下载到本地就看你环境了。我用的是requests加上UA伪装因为很多图片接口会校验Referer头。一个实测有效的处理方式是import requests def download_image(img_url, save_path): headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36, Referer: https://example.com/, } resp requests.get(img_url, headersheaders, timeout10) with open(save_path, wb) as f: f.write(resp.content)3.2 三种缺口识别方案及原理拿到背景图和滑块拼图之后识别缺口位置有几条不同的技术路线。我分别说完它们的原理、代码和适用条件你可以看情况选用。方案一模板匹配法模板匹配的思路最简单滑块拼图是什么样就在背景大图里找最相似的地方。OpenCV的cv2.matchTemplate会用模板在图像上滑动计算每个位置的相似度相似度最高的点就是缺口位置。对应代码import cv2 import numpy as np def find_gap_with_template(bg_path, tp_path, offset_x0, offset_y0): bg cv2.imread(bg_path, cv2.IMREAD_COLOR) tp cv2.imread(tp_path, cv2.IMREAD_COLOR) # 模板匹配, TM_CCOEFF_NORMED 对光照变化相对鲁棒 result cv2.matchTemplate(bg, tp, cv2.TM_CCOEFF_NORMED) _, _, _, max_loc cv2.minMaxLoc(result) return max_loc[0] offset_x, max_loc[1] offset_y这个方案的优点是实现非常快代码量少缺点是要求滑块拼图和缺口处的小图高度相似一旦验证码为了增加难度对缺口做了阴影或描边处理或者拼图尺寸和缺口不一致效果就会打折。方案二背景与原始图对比法有些验证码页面上除了带缺口的背景图还能拿到一张不带缺口的原始背景图。只要你把两张图都下载下来直接做像素差缺口位置就能以极高精度暴露出来。def find_gap_with_bg_diff(bg_path, raw_path): bg cv2.imread(bg_path) raw cv2.imread(raw_path) diff cv2.absdiff(bg, raw) gray cv2.cvtColor(diff, cv2.COLOR_BGR2GRAY) _, thresh cv2.threshold(gray, 60, 255, cv2.THRESH_BINARY) # 找最大轮廓 contours, _ cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) max_contour max(contours, keycv2.contourArea) x, y, w, h cv2.boundingRect(max_contour) return x w // 2, y h // 2这个方案识别准确率在所有方案中最稳命中率几乎百分之百但最关键的限制在于“能不能拿到无缺口原图”。很多风控系统不会把原图暴露在前端资源里所以要看你测试的目标页面是否给机会。方案三边缘检测与形态学处理如果拿不到原图也拿不到可靠的滑块图还可以直接对带缺口的背景图做边缘检测。缺口的边框通常是一圈高对比度的轮廓而图像内部虽然内容丰富但在边缘图里往往是连续的纹理线条。通过Canny得到边缘后再分析整行边缘密度的突变区可以追踪到缺口的位置。def find_gap_with_edge(bg_path): bg cv2.imread(bg_path) gray cv2.cvtColor(bg, cv2.COLOR_BGR2GRAY) # 高斯模糊减少纹理干扰 blurred cv2.GaussianBlur(gray, (5, 5), 0) edges cv2.Canny(blurred, 100, 200) # 按列统计边缘点密度缺口附近会有明显的局部高亮区块 col_sum np.sum(edges, axis0) threshold max(col_sum) * 0.7 candidate_cols [i for i, v in enumerate(col_sum) if v threshold] return min(candidate_cols)我在实际项目里用得最多的组合是“方案二为主、方案三兜底”。一个原因是只需要少量代码改动就能切换另一个原因是当页面资源结构变化时不至于整个脚本直接报废。3.3 像素距离如何换算成实际拖拽像素这里有个特别容易被新手忽略的重灾区图像缺口在图片上的像素坐标和浏览器页面上拖动滑块所需的像素距离不完全等同。原因在于网页上的背景图通常会有缩放可能CSS把图片显示成300px宽而原始图片是500px宽。如果你直接把OpenCV算出来的像素距离给Selenium用误差会很大。换算办法是在前端获取图片元素的实际渲染尺寸和自然尺寸def get_image_scale(driver, img_selector): img driver.find_element(By.CSS_SELECTOR, img_selector) natural_width img.size[width] # 实际渲染宽度 # 也可以通过JS取自然宽度 natural_width_js driver.execute_script(return arguments[0].naturalWidth, img) display_width driver.execute_script(return arguments[0].clientWidth, img) return display_width / natural_width_js之后计算真实位移就是gap_x_in_image 180 # OpenCV算出的缺口x坐标 scale 0.8 # 页面显示宽度 / 图片原始宽度 real_distance gap_x_in_image * scale还要注意滑块手柄本身占据了一些宽度所以最终移动距离往往要在real_distance基础上再减去一个起始偏移量。这个偏移量不是固定的我第一次适配某系统时是20px换一个业务系统又变成18px最好是在本地先跑几次拖拽观察实际落点和缺口中心的偏差再把这个系统误差写进配置。4. 模拟真人拖拽轨迹的核心细节4.1 为什么直接拖拽大概率失败拿到目标距离直接调ActionChains(driver).drag_and_drop_by_offset(slider, distance, 0).perform()在弱风控的地方偶尔能过但稍微正规点的验证码系统几乎必挂。原因要从行为检测角度理解。真人拖动滑块的过程大致是先快速移动接近目标时减速到目标附近有个短暂的微调过程最后停顿一下再松手。机器直接拖拽是起点到终点接近匀速的瞬时位移位移曲线太干净没有加速度变化和人类操作的噪声。部分验证码系统还会记录鼠标按下去到抬起来的时间、每帧移动的坐标序列、是否出现抖动、是否发生回弹。这套特征组合判断下来机器操作和真人操作的差异十分明显。4.2 拖拽轨迹的生成算法我用的轨迹生成算法是三段式思路核心是模拟人类手部运动的加速度变化。代码很长但逻辑可以拆成三步加速启动从按下鼠标到开始移动会有短暂停顿然后从低速快速加速。中段巡航以较高速移动到目标距离的70%~85%区间。减速微调接近缺口时减速并且允许在目标位置附近来回小幅修正。这里是一段可以直接用的轨迹生成函数import random import time def generate_track(distance): track [] current 0 mid distance * random.uniform(0.7, 0.85) # 初始停顿模拟真人按下滑块后的短暂反应 t random.uniform(0.1, 0.3) move 0 while current distance: if current mid: # 加速阶段 move random.randint(8, 20) else: # 减速阶段 move random.randint(2, 7) current move track.append(current) time.sleep(random.uniform(0.01, 0.03)) # 修正确保最后一个点正好在目标附近允许轻微误差 track[-1] distance return track这个函数生成的是位移序列真正执行拖拽时要按序列逐步移动。需要注意一点current累加过程里可能超过目标距离所以循环末尾直接强制设为distance同时移动的步长和随机停顿范围需要根据实际页面灵敏度调整。如果页面比较敏感步子太大容易被判定异常就用2~5范围的小步长。4.3 执行拖拽的完整操作有了轨迹序列执行阶段要用ActionChains分步移动from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.common.by import By def drag_slider(driver, slider, track): action ActionChains(driver) # 1. 按住滑块 action.click_and_hold(slider).perform() # 2. 按轨迹移动 for pos in track: current_x slider.location[x] target_x current_x (pos - track[track.index(pos)-1] if track.index(pos) 0 else pos) action.move_by_offset(target_x - current_x, random.uniform(-1.5, 1.5)).perform() time.sleep(random.uniform(0.01, 0.05)) # 3. 松开 action.release().perform()这个写法的思路是每一步都基于滑块元素当前实际位置计算偏移差而不是直接从一个固定的绝对初值累加。因为move_by_offset是基于当前鼠标位置的相对移动如果中间某一步出现偏差后面还按累计值计算就会越来越歪。基于当前位置计算虽然麻烦一点但鲁棒性明显更好。有一个细节拖拽过程中给y轴加一个轻微的随机偏移是刻意为之。真人拖滑块不可能绝对水平总会有一点上下浮动。我在多个项目里测试过y轴完全不动和带一点浮动的成功率差距在15%左右所以别嫌麻烦。注意有些页面监听的是滑块元素的样式变化ActionChains拖不动的时候可以改用JS模拟鼠标事件的方式。不过这不是常规推荐路径因为JS事件模拟会丢失大量真实鼠标事件的细节特征更容易被风控识别。最好的方案还是保持真实鼠标操作。5. 完整实现从搭建到跑通的实战流程5.1 整体流程梳理整个通过滑块验证码的流程可以划分为六个步骤创建浏览器driver并访问目标页面。等待滑块验证码出现定位滑块手柄和背景图元素。下载背景图到本地同时尝试获取无缺口原图和滑块拼图。图像识别缺口位置计算像素距离并换算成页面位移。生成人类化拖拽轨迹执行拖拽。验证是否通过检查滑块是否消失、校验结果元素是否出现、URL或页面状态是否跳转。流程看起来简单但每一步之间都有隐含的等待条件。我封装成一个类来组织这些逻辑每个环节独立成方法这样单个环节升级或替换时不会影响其他部分。5.2 完整代码示例这里给出一套可以在自己测试环境里跑的完整示例。这个示例里我虚构了一个测试页面只用来说明整体代码的组织方式。实际使用时替换元素定位和URL即可。import time import random import cv2 import numpy as np import requests import undetected_chromedriver as uc from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.action_chains import ActionChains class SliderCracker: def __init__(self, url): self.url url self.driver self._create_driver() def _create_driver(self): options uc.ChromeOptions() options.add_argument(--window-size1920,1080) options.add_argument(--disable-blink-featuresAutomationControlled) options.add_argument(--no-first-run) options.add_argument(--no-default-browser-check) driver uc.Chrome(optionsoptions) return driver def _wait_slider(self): return WebDriverWait(self.driver, 15).until( EC.presence_of_element_located((By.CSS_SELECTOR, div.slider)) ) def _download_image(self, url, path): headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36, Referer: self.url, } r requests.get(url, headersheaders, timeout10) with open(path, wb) as f: f.write(r.content) def _find_gap(self, bg_path, tp_pathNone, raw_pathNone): if raw_path: # 优先使用原图对比 bg cv2.imread(bg_path) raw cv2.imread(raw_path) diff cv2.absdiff(bg, raw) gray cv2.cvtColor(diff, cv2.COLOR_BGR2GRAY) _, thresh cv2.threshold(gray, 60, 255, cv2.THRESH_BINARY) contours, _ cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) c max(contours, keycv2.contourArea) x, _, _, _ cv2.boundingRect(c) return x elif tp_path: bg cv2.imread(bg_path) tp cv2.imread(tp_path) result cv2.matchTemplate(bg, tp, cv2.TM_CCOEFF_NORMED) _, _, _, max_loc cv2.minMaxLoc(result) return max_loc[0] else: bg cv2.imread(bg_path) gray cv2.cvtColor(bg, cv2.COLOR_BGR2GRAY) blurred cv2.GaussianBlur(gray, (5, 5), 0) edges cv2.Canny(blurred, 100, 200) col_sum np.sum(edges, axis0) threshold max(col_sum) * 0.7 candidates [i for i, v in enumerate(col_sum) if v threshold] return min(candidates) def _generate_track(self, distance): track [] current 0 mid distance * random.uniform(0.7, 0.85) while current distance: if current mid: move random.randint(8, 20) else: move random.randint(2, 7) current move track.append(current) time.sleep(random.uniform(0.01, 0.03)) track[-1] distance return track def _drag(self, slider, track): action ActionChains(self.driver) action.click_and_hold(slider).perform() prev_pos 0 for pos in track: offset pos - prev_pos action.move_by_offset(offset, random.uniform(-1.5, 1.5)).perform() prev_pos pos time.sleep(random.uniform(0.01, 0.05)) action.release().perform() def crack(self): self.driver.get(self.url) slider self._wait_slider() # 假设页面元素滑块缺口背景图、原图 bg_url https://example.com/bg.jpg raw_url https://example.com/raw.jpg self._download_image(bg_url, bg.jpg) self._download_image(raw_url, raw.jpg) gap_x self._find_gap(bg.jpg, raw_pathraw.jpg) # 缩放换算 scale 0.8 distance int(gap_x * scale) track self._generate_track(distance) self._drag(slider, track) time.sleep(1) # 判断是否成功 try: self.driver.find_element(By.CSS_SELECTOR, div.slider) print(需要重试) except Exception: print(验证通过)这段代码的组织方式是每个方法职责单一便于测试排查。实际项目里你还会遇到目标元素加载慢、图片请求需要额外鉴权、验证码嵌套在iframe里等情况这些都需要在各个环节内做好异常处理。5.3 关于图片下载和缺口定位的必要补充说明上面示例中的图片URL我写的是固定示例。实际页面中图片地址经常不是直接写在img标签的src里而是放在内联样式背景图或动态加载的接口里。处理这类问题我的经验是先去浏览器开发者工具的Network面板看验证码出现时前端请求了哪些图片资源把它们和DOM里的元素对应上。另外有些验证码图片是带base64数据直接在JS里渲染的那就需要直接用Selenium执行JS来取数据并转存本地没法通过requests直接下载。最常见的实际坑是图片地址有防盗链直接下载会返回403或一张提示图片。解决思路是加上Referer和Origin头目标域名从当前页面URL解析出来。遇到加上Referer还是不行的情况就得用Selenium的execute_script在浏览器里发起请求获取图片数据因为浏览器里发请求天然带着正确的身份和cookie。6. 高频踩坑与排查实录这一节我按自己在多个项目里遇到的真实问题来整理希望能帮你省点时间。6.1 图片加载不完整导致识别失败背景图是用懒加载渲染的脚本执行太快图片还没下载完就截图或下载。最直观的表现是识别出来的坐标在图片边缘或者干脆识别不到明显的缺口。解决办法在截取或下载图片前增加等待时间使用WebDriverWait等待图片元素出现然后再执行图像下载。另外在执行拖拽前最好检查一下滑块是否处于可交互状态不要在验证码还在加载过程中就动手。6.2 元素定位失败验证码在iframe里现在很多验证码是iframe嵌入的直接在主文档里找元素肯定找不到。处理方法是先切换到iframe操作完成后再切回主文档。from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC frame WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.CSS_SELECTOR, iframe#captcha-frame)) ) driver.switch_to.frame(frame) # 操作完成后切回主文档 driver.switch_to.default_content()iframe的id或class每个页面不同定位时用css selector或xpath都可以关键是必须等它渲染完成再切换。6.3 ActionChains拖拽失灵的真正原因如果你确认元素定位没问题图片识别也没问题但拖拽执行后滑块纹丝不动我有过一次排查经历那个页面的滑块监听的是mousedown、mousemove、mouseup事件而ActionChains在移动过程中没有持续触发足够的事件。解决办法是在生成轨迹时增加小步长比如从8~20改成3~6这样鼠标移动的每一步更密事件触发更频繁。移动步长太粗时虽然坐标最终到位但事件序列太稀疏页面端无法捕捉运动过程。另外如果页面在click_and_hold之后很久没有移动事件滑块可能自动复位所以开始拖动前要控制好节奏不要在按压后等待过久。6.4 坐标算对了但总差一点点如果你计算出的距离和实际目标位置总是存在固定的偏差多半是以下原因背景图元素有边框或内边距导致实际图片渲染位置和你从图像文件里算的坐标不一致。滑块手柄的起始位置不是最左端元素本身带有一定的初始偏移。页面有整体缩放或者元素有transform变换。遇到这种情况不要反复微调识别算法而是改用“人工标定法”手动把滑块拖到正确位置记录此时滑块元素的x坐标和背景图片缺口的x坐标做一次差值写进配置里。这个方法我在好几个系统上都验证过比纯靠像素换算稳定得多。6.5 Selenium检测导致的额外弹窗如果你发现验证码出现的频率异常高或者页面在启动后直接提示环境异常十有八九是浏览器自动化痕迹太明显。常规处理思路有使用undetected-chromedriver。通过Chrome DevTools ProtocolCDP屏蔽自动化相关属性。使用真实用户配置的浏览器profile而不是每次新建空白配置。def create_stealth_driver(): options uc.ChromeOptions() options.add_argument(--user-data-dirC:/Users/yourname/AppData/Local/Google/Chrome/User Data) driver uc.Chrome(optionsoptions) return driver用真实user-data-dir的代价是会带上你日常浏览器的缓存和登录状态对测试数据隔离有一定影响适合本地调试不适合放在CI环境里全自动跑。6.6 高频问题速查表现象可能原因解决方案滑块找不到在iframe内、懒加载未完成切换到iframe增加显式等待缺口识别位置偏左/偏右图片缩放比例未换算用自然宽高比算scale再乘拖拽后滑块不移动mousemove事件触发不足缩短移动步长增加事件密度总是差固定像素元素边框/起始偏移人工标定一次偏移量写入配置识别准确但无法通过验证行为轨迹太规整增加随机停顿、y轴浮动、回弹微调页面提示环境异常自动化指纹特征明显用undetected-chromedriver禁用自动化提示条7. 成功率提升的进阶经验7.1 轨迹参数与随机模块的平衡对着同一个页面跑多了会发现滑块验证码好像有“记忆”一样总是在你脚本即将通过的时候突然变严格。我测试过几十次后的一点体会是轨迹参数不能写成死值必须在合理区间内动态随机。但随机也不能太离谱否则真实感下降成功率反而变低。我调参后的取值范围大致是这样起始等待时间0.1到0.4秒加速段步长8到18减速段步长1到5每次移动间隔0.01到0.04秒y轴浮动范围-2到2像素最后松手前停顿0.2到0.5秒这些数值来自对真人鼠标行为的近似模拟不同页面可能有差异。使用者应该根据自己目标页面的验证码灵敏度调整原则是步长适中节奏要有变化不要让移动轨迹看起来像一个固定的采样函数。7.2 失败后的自动重试策略一次拖拽失败不要立刻再来一次一模一样的操作。有些风控系统对连续失败次数很敏感连续失败三次后就会升级验证码难度甚至直接锁住账号一段时间。我的重试策略是第一次失败后重新获取缺口位置因为可能这次图片的缺口和上次不同。执行一次清理操作比如把滑块拖回起点。等待随机1~3秒再重试。最多重试3次连续失败就发出告警让测试人员人工介入。7.3 单测与回归验证的维护方式这类脚本最容易出现的问题是页面改版后细微变化导致整套脚本全挂。所以我强烈建议把校验逻辑独立成函数并且每次跑自动化测试时都记录截图、缺口坐标、最终位移和执行结果。这样即使某天失败了也有现场数据帮助你判断是图像识别环节崩了还是拖拽行为被风控拦截了。我通常会保存这类日志字段页面URL、背景图URL、识别方式、缺口坐标、计算距离、实际拖拽距离、是否成功、耗时。累积一段时间后这些数据能直接看出哪个环节成功率最低。8. 一些更本质的想法有一次我连续调了两天代码把某系统的滑块验证码通过率从50%拉到了90%左右但就在第三天对方在验证码缺口图上加了纹理噪声我的边缘检测方案一下全废只能连夜换模板匹配方案。那个晚上我一直在想自动化测试和验证码风控就像一场没有终点的拉锯战永远不能指望一套方案一劳永逸。后来我调整了心态和代码架构把整个滑块方案做成了高度模块化的组件。识别缺口的部分支持多种策略自由切换拖拽轨迹的参数全部外置成配置文件这样就算验证码升级我也能在半小时内切到另一个策略而不是从头写一遍。所以如果你要长期维护这类自动化测试脚本设计上最好早做考虑。不要太依赖某一个识别算法的精妙而要把关注点放在如何快速应对变化上。最后再分享一个实用的小技巧很多滑块验证码在执行通过之后会有一段空白动画或者校验状态提示。这时候别急着进行下一步操作多等0.5秒到1秒确认页面状态完全稳定后再继续可以避免很多后续步骤因为页面元素尚未就绪而产生的失败。这个不起眼的小细节能把整套流程的综合通过率再往上拉几个百分点。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑