【python+selenium】极验滑动验证码的实现
2019-05-17 本文已影响117人
米兰的小铁匠
效果gif
前言
在上次做完图形验证码后,发现识别率不尽人意,可以说是很不满意,稍微有点更多的干扰,打印出来的字符一塌糊涂!这次转手对极验的滑动验证码进行识别。。。
- 目前市面上越来越多的网站的注册登录用滑动验证码进行验证,与人互动的形式来判定你是不是人类操作,所以说,我们要进行破解,就是模仿人体操作进行识别与通过验证!
- 还有一些注意问题后面说,通常也是识别不成功的关键!
- 识别率估摸着有90%以上了!
正序
- 要用到的:selenium、PIL、io、Chrome浏览器、还有驱动浏览器的插件chromediver
流程逻辑
- 打开网页,进入验证页面
- 点击验证按钮,获取完整图片与带缺口的图片进行比对(现在的极验验证码已经不能直接获取完整图片了。。。)
- 计算偏移量
- selenium控制滑块填补空缺,验证完成!
- 封装类,多个方法实现功能
- 初始化值,打开网页,程序完成自动结束!
class CrackGeetest():
def __init__(self):
self.url = 'https://www.geetest.com/type/'
self.browser = webdriver.Chrome()
self.wait = WebDriverWait(self.browser, 20)
# 程序完成,自动结束程序
def __del__(self):
self.browser.close()
def open(self):
"""
打开网页
:return: None
"""
self.browser.get(self.url)
- 进入验证页面,获取验证按钮与验证码的位置
def get_geetest_button(self):
"""
获取初始验证按钮
:return:
"""
# 验证按钮
button = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'geetest_radar_tip')))
return button
def get_position(self):
"""
获取验证码位置
:return: 验证码位置元组
"""
img = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'geetest_canvas_img')))
print('img')
location = img.location
size = img.size
top, bottom, left, right = location['y'], location['y'] + size['height'], location['x'], location['x'] + size[
'width']
return (top, bottom, left, right)
- 这个时候,就可以看到带缺口图片验证的界面
- 之前的极验验证码是会出现完整图片。现在直接就显示了带缺口图片的验证,通过搜罗网上的一些解决方法,发现有一个study隐藏属性:
如果把这个属性删除就会出现完整图片:
通过对CSS的更改,所以这样我们就能获取完整图片 - 同时获取带缺口的图片加入带缺口图片进行对比,获取偏移量!(PIL)
def get_screenshot(self):
"""
获取网页截图
:return: 截图对象
"""
screenshot = self.browser.get_screenshot_as_png()
screenshot = Image.open(BytesIO(screenshot))
return screenshot
def get_geetest_image(self, name='captcha.png'):
"""
获取验证码图片
:return: 图片对象
"""
top, bottom, left, right = self.get_position()
print('验证码位置', top, bottom, left, right)
screenshot = self.get_screenshot()
captcha = screenshot.crop((left, top, right, bottom))
captcha.save(name)
return captcha
def delete_style(self):
'''
执行js脚本,获取无滑块图
:return None
'''
js = 'document.querySelectorAll("canvas")[2].style=""'
self.browser.execute_script(js)
def get_gap(self, image1, image2):
"""
获取缺口偏移量
:param image1: 带缺口图片
:param image2: 不带缺口图片
:return:
"""
left = 60
print(image1.size[0])
print(image1.size[1])
for i in range(left, image1.size[0]):
for j in range(image1.size[1]):
if not self.is_pixel_equal(image1, image2, i, j):
left = i
return left
return left
def is_pixel_equal(self, image1, image2, x, y):
"""
判断两个像素是否相同
:param image1: 图片1
:param image2: 图片2
:param x: 位置x
:param y: 位置y
:return: 像素是否相同
"""
# 取两个图片的像素点
pixel1 = image1.load()[x, y]
pixel2 = image2.load()[x, y]
threshold = 60
if abs(pixel1[0] - pixel2[0]) < threshold and abs(pixel1[1] - pixel2[1]) < threshold and abs(
pixel1[2] - pixel2[2]) < threshold:
return True
else:
return False
- 然后我们根据偏移量获取移动轨迹,控制滑块,填补缺口!
- 由于验证码的特殊性,我们是不能控制滑块匀速滑过去的(人类是做不到的),极验在此也是做了验证的!所以我们按照人操作,先加速后减速做个优化!
def get_track(self, distance):
"""
根据偏移量获取移动轨迹
:param distance: 偏移量
:return: 移动轨迹
"""
# 移动轨迹
track = []
# 当前位移
current = 0
# 减速阈值
mid = distance * 4 / 5
# 计算间隔
t = 0.2
# 初速度
v = 0
while current < distance:
if current < mid:
# 加速度为正2
a = 2
else:
# 加速度为负3
a = -1
# 初速度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 move_to_gap(self, slider, track):
"""
拖动滑块到缺口处
:param slider: 滑块
:param track: 轨迹
:return:
"""
ActionChains(self.browser).click_and_hold(slider).perform()
for x in track:
ActionChains(self.browser).move_by_offset(xoffset=x, yoffset=0).perform()
time.sleep(0.5)
ActionChains(self.browser).release().perform()
注意问题
-
不管是电脑设置还是浏览器设置的缩放都要改成100%!!!!
设置
浏览器
否则就会影响图片的截取与偏移量的错误计算,总的来说就是识别会失败!!!(话说我就因为系统设置没改,栽在这有段时间了。。。)
- 其他的问题,无非就是插件版本不对、编写代码等问题。