Python自动化中动态与滑动验证码的降噪及识别方案
本文详解Python自动化操作中动态与滑动验证码的处理方案。针对动态验证码,建议通过页面截图裁剪避免请求失效;针对滑动验证码,重点讲解缺口识别与拟人化轨迹模拟。此外,深入解析灰度化、二值化及噪点过滤等降噪步骤,并对比Tesserocr与第三方接口的识别优劣,提供完整的自动化验证实现思路。
前言
在Python自动化操作中,动态验证码与滑动验证码的降噪及识别是常见难点。许多开发者在处理此类验证码时,常因识别流程不当而遭遇困难。本文将详细解析不同验证码类型的处理逻辑与识别方法,帮助解决自动化过程中的验证障碍。
一、动态验证码
- 动态验证码由服务端生成,每次点击或请求都会刷新内容。这导致许多人在识别过程中发现验证码频繁失效,无法完成验证。
- 造成这一问题的原因在于,若直接下载图片进行识别,下载请求本身即被视为一次点击操作,导致验证码内容在识别前已更新失效。
- 最佳实践是在打开页面后,对当前页面进行整体截图,随后定位验证码在截图中的坐标位置,将验证码区域从截图中裁剪出来进行识别。这种方法避免了额外的网络请求,从而防止验证码因刷新而失效。

from selenium import webdriver
from PIL import Image
# 实例化浏览器
driver = webdriver.Chrome()
# 最大化窗口
driver.maximize_window()
# 打开登陆页面
driver.get(# 你的url地址)
# 保存页面截图
driver.get_screenshot_as_file('./screen.png')
# 定位验证码的位置
location = driver.find_element_by_id('login_yzm_img').location
size = driver.find_element_by_id('login_yzm_img').size
left = location['x']
top = location['y']
right = location['x'] + size['width']
bottom = location['y'] + size['height']
# 裁剪保存
img = Image.open('./screen.png').crop((left,top,right,bottom))
img.save('./code.png')
driver.quit()
二、滑动验证码
- 滑动验证码通常包含两张图片:一张背景大图和一张带有缺口的小滑块图片。验证过程要求将小滑块拖动至大图片的缺口处,实现重合即可通过验证。
- 处理滑动验证码的核心在于识别大图片中缺口的位置,计算小滑块需要滑动的距离,并控制滑块移动至该位置。
- 为了使滑动过程更加拟人化,避免被风控系统检测为机器行为,需要生成模拟人类滑动轨迹的路径,而非简单的直线移动。

# 下载两个滑块
bg = self.driver.find_element_by_xpath('//*[@id="captcha_container"]/div/div[2]/img[1]').get_attribute('src')
slider = self.driver.find_element_by_xpath('//*[@id="captcha_container"]/div/div[2]/img[2]').get_attribute('src')
request.urlretrieve(bg, os.getcwd() + '/bg.png')
request.urlretrieve(slider, os.getcwd() + '/slider.png')
# 获取两个滑块偏移量方法
def getGap(self, sliderImage, bgImage):
'''
Get the gap distance
:param sliderImage: the image of slider
:param bgImage: the image of background
:return: int
'''
bgImageInfo = cv2.imread(bgImage, 0)
bgWidth, bgHeight = bgImageInfo.shape[::-1]
bgRgb = cv2.imread(bgImage)
bgGray = cv2.cvtColor(bgRgb, cv2.COLOR_BGR2GRAY)
slider = cv2.imread(sliderImage, 0)
sliderWidth, sliderHeight = slider.shape[::-1]
res = cv2.matchTemplate(bgGray, slider, cv2.TM_CCOEFF)
a, b, c, d = cv2.minMaxLoc(res)
# print(a,b,c,d)
# 正常如下即可
# return c[0] if abs(a) >= abs(b) else d[0]
# 但是头条显示验证码的框跟验证码本身的像素不一致,所以需要根据比例计算
if abs(a) >= abs(b):
return c[0] * bgWidth / (bgWidth - sliderWidth)
else:
return d[0] * bgWidth / (bgWidth - sliderWidth)
# 移动路径方法
def getTrack(self, distance):
'''
Get the track by the distance
:param distance: the distance of gap
:return: list
'''
# 移动轨迹
track = []
# 当前位移
current = 0
# 减速阈值
mid = distance * 4 / 5
# 计算间隔
t = 0.2
# 初速度
v = 0
while current < distance:
if current < mid:
# 加速度为正2
a = 2
else:
# 加速度为负3
a = -3
# 初速度v0
v0 = v
# 当前速度v = v0 + at
v = v0 + a * t
# 移动距离x = v0t + 1/2 * a * t^2
move = v0 * t + 1 / 2 * a * t * t
# 当前位移
current += move
# 加入轨迹
track.append(round(move))
return track
# 滑动到缺口位置
def moveToGap(self, track):
'''
Drag the mouse to gap
:param track: the track of mouse
:return: None
'''
ActionChains(self.driver).click_and_hold(self.driver.find_element_by_xpath('//*[@id="captcha_container"]/div/div[3]/div[2]/div[2]/div')).perform()
while track:
x = random.choice(track)
ActionChains(self.driver).move_by_offset(xoffset=x, yoffset=0).perform()
track.remove(x)
time.sleep(0.5)
ActionChains(self.driver).release().perform()
三、验证码的降噪
验证码降噪旨在去除图像中多余的线条和干扰元素,提升后续识别的准确率。
降噪处理的第一步是将彩色图像转换为灰度图像,以降低数据维度。


img = cv2.imread('yzm.png')
# 将图片灰度化处理,降维,加权进行灰度化c
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
cv2.imshow('min_gray',gray)
cv2.waitKey(0)
cv2.destroyAllWindows()
第二步是对灰度图像进行二值化处理,将图像转化为黑白两色,突出字符或图形特征。

import cv2
img = cv2.imread('yzm.png')
# 将图片灰度化处理,降维,加权进行灰度化c
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
t,gray2 = cv2.threshold(gray,220,255,cv2.THRESH_BINARY)
cv2.imshow('threshold',gray2)
cv2.waitKey(0)
cv2.destroyAllWindows()
第三步是进行噪点过滤,去除二值化后残留的孤立像素点或细小干扰线。

import cv2
img = cv2.imread('yzm.png')
# 将图片灰度化处理,降维,加权进行灰度化c
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
t,gray2 = cv2.threshold(gray,220,255,cv2.THRESH_BINARY)
def remove_noise(img, k=4):
img2 = img.copy()
# img处理数据,k过滤条件
w, h = img2.shape
def get_neighbors(img3, r, c):
count = 0
for i in [r - 1, r, r + 1]:
for j in [c - 1, c, c + 1]:
if img3[i, j] > 10: # 纯白色
count += 1
return count
# 两层for循环判断所有的点
for x in range(w):
for y in range(h):
if x == 0 or y == 0 or x == w - 1 or y == h - 1:
img2[x, y] = 255
else:
n = get_neighbors(img2, x, y) # 获取邻居数量,纯白色的邻居
if n > k:
img2[x, y] = 255
return img2
result = remove_noise(gray2)
cv2.imshow('8neighbors', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
四、验证码的识别
传统上可使用tesserocr库进行验证码识别,但该库局限性较大,识别率较低。即使经过良好的降噪处理,若图像中仍有少量干扰线条,识别结果仍可能不准确,因此该方法并不十分推荐。
目前更常见的做法是接入第三方图片识别接口,例如阿里云或腾讯提供的图像识别服务。
使用这些第三方接口需要开发者自行集成相应的识别API,通过调用接口获取识别结果。
#识别降噪后的图片
code = tesserocr.image_to_text(nrImg)
#消除空白字符
code.strip()
#打印
print(code)
总结
本文介绍了Python自动化操作中动态验证码与滑动验证码的降噪及识别方法。更多相关技术细节,建议参考本站过往文章或继续浏览后续内容,感谢支持。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









