如何用Selenium处理限6次尝试的拼图验证码?
解决极验拼图验证码的6次分段移动问题
你当前的代码存在两个核心问题:
- 每次循环都重新点击并释放滑块,相当于多次独立滑动操作,会快速耗尽6次尝试机会
- 移动的是绝对偏移量(每次从起点移到固定x位置),而非分段的相对偏移,完全没利用6次尝试的限制逻辑
核心思路
要在6次内完成验证,必须先计算滑块需要移动的总距离,再将总距离拆分为6段逐步调整(或直接模拟人类滑动轨迹一次完成,避免浪费尝试次数)。
步骤1:计算滑块总移动距离
极验拼图的缺口位置可通过对比「完整背景图」和「带缺口背景图」的像素差异获取(需安装Pillow库):
from PIL import Image import numpy as np import base64 from io import BytesIO def get_gap_distance(driver): # 定位验证码的两个canvas元素(需根据页面实际结构调整选择器) canvas_full = driver.find_element(By.CSS_SELECTOR, 'canvas.geetest_canvas_fullbg') canvas_slice = driver.find_element(By.CSS_SELECTOR, 'canvas.geetest_canvas_bg') # 将canvas转换为Image对象 def canvas_to_img(canvas): img_base64 = driver.execute_script("return arguments[0].toDataURL('image/png').substring(21);", canvas) img_bytes = base64.b64decode(img_base64) return Image.open(BytesIO(img_bytes)) img_full = canvas_to_img(canvas_full) img_slice = canvas_to_img(canvas_slice) # 对比像素差异,定位缺口x坐标 diff = np.abs(np.array(img_full) - np.array(img_slice)).sum(axis=2) gap_x = np.argmax(diff.mean(axis=0)) # 计算滑块初始位置与缺口的差值(补偿滑块自身宽度误差) slider = driver.find_element(By.CLASS_NAME, 'geetest_slider_button') slider_x = slider.location['x'] return gap_x - slider_x - 10
步骤2:按6段拆分移动滑块
如果必须严格分6次移动,可按以下方式实现(保持滑块按住状态,分段相对移动):
import time from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.common.by import By try: slider = driver.find_element(By.CLASS_NAME, 'geetest_slider_button') total_distance = get_gap_distance(driver) if total_distance <= 0: print("无需移动滑块") pass step = total_distance / 6 actions = ActionChains(driver) # 按住滑块开始移动 actions.click_and_hold(slider).perform() time.sleep(0.1) # 分6次完成分段移动 for _ in range(6): actions.move_by_offset(step, 0).perform() time.sleep(0.05) # 模拟人类移动的微小停顿 actions.release().perform() time.sleep(1) except Exception as e: print(f'滑块处理出错: {str(e)}')
更优方案:一次模拟人类滑动轨迹
其实没必要分6次尝试,模拟人类先快后慢的滑动轨迹,一次就能完成验证,避免触发封禁逻辑:
def human_like_slide(actions, total_distance): # 快速移动80%距离 actions.move_by_offset(total_distance * 0.8, 0).perform() time.sleep(0.08) # 减速移动15%距离 actions.move_by_offset(total_distance * 0.15, 0).perform() time.sleep(0.1) # 最后微调剩余5%距离 actions.move_by_offset(total_distance * 0.05, 0).perform() time.sleep(0.05) try: slider = driver.find_element(By.CLASS_NAME, 'geetest_slider_button') total_distance = get_gap_distance(driver) if total_distance <= 0: pass actions = ActionChains(driver) actions.click_and_hold(slider).perform() human_like_slide(actions, total_distance) actions.release().perform() time.sleep(1) except Exception as e: print(f'滑块处理出错: {str(e)}')
注意事项
- 极验的canvas元素选择器可能随网站更新变化,需根据实际页面结构调整
- 图片对比时要确保页面无缩放,避免坐标偏差
- 即使通过验证码,短时间大量请求仍会触发封禁,需控制请求频率
内容的提问来源于stack exchange,提问作者SolidOpt
相关产品推荐
相关产品推荐

