利用selenium库自动执行滑动验证码模拟登陆
破解流程
#1、输入账号、密码,然后点击登陆
#2、点击按钮,弹出没有缺口的图
#3、针对没有缺口的图片进行截图
#4、点击滑动按钮,弹出有缺口的图
#5、针对有缺口的图片进行截图
#6、对比两张图片,找出缺口,即滑动的位移
#7、按照人的行为行为习惯,把总位移切成一段段小的位移
#8、按照位移移动
#9、完成登录
模拟登陆案例一:
from selenium import webdriver
from selenium.webdriver import ActionChains
from PIL import Image
import time
import random
option = webdriver.ChromeOptions()
# 添加启动参数 (add_argument)
option.add_argument('disable-infobars') # 禁用浏览器正在被自动化程序控制的提示
driver = webdriver.Chrome(chrome_options=option)
def get_snap(driver):
# selenium自带的截图网页全屏图片
driver.save_screenshot('snap.png')
# 拿到验证图片所在的标签,方便确认位置
img = driver.find_element_by_class_name('geetest_canvas_img')
# location 代表该图片在整个页面所在的位置(x, y),x:距离左边多长,y:距离上面多长
# print(img.location)
# size 代表该图片的大小
# print(img.size)
left = img.location.get('x')
upper = img.location.get('y')
right = left + img.size.get('width')
lower = upper + img.size.get('height')
# 拿到图片四个边的位置,就可以进行裁剪图片了
# print(left, upper, right, lower)
img_obj = Image.open('snap.png')
# 对屏幕进行裁剪,获取滑动验证码图片
image = img_obj.crop((left, upper, right, lower))
# image.show()
return image
# 获取完整图片
def get_img1(driver):
time.sleep(0.2)
js_code = """
var x = document.getElementsByClassName('geetest_canvas_fullbg')[0].style.display="block";
console.log(x)
"""
# 执行js代码
driver.execute_script(js_code)
time.sleep(1)
# 截取图片
img_obj = get_snap(driver)
return img_obj
# 获取有缺口的图片
def get_img2(driver):
time.sleep(0.2)
js_code = """
var x = document.getElementsByClassName('geetest_canvas_fullbg')[0].style.display="none";
console.log(x)
"""
# 执行js代码
driver.execute_script(js_code)
time.sleep(1)
# 截取图片
img_obj = get_snap(driver)
return img_obj
def get_distance(img1, img2):
# 初始值
start = 60
# 模块色差
color_num = 60
for x in range(start, img1.size[0]):
for y in range(img1.size[1]):
rgb1 = img1.load()[x, y]
rgb2 = img2.load()[x, y]
# abs 获取绝对值
r = abs(rgb1[0] - rgb2[0])
g = abs(rgb1[1] - rgb2[1])
b = abs(rgb1[2] - rgb2[2])
if not (r < color_num and g < color_num and b < color_num):
return x - 7 # 误差值大概为7
def get_stacks(distance):
distance += 20
'''
拿到移动轨迹,模仿人的滑动行为,先匀加速后匀减速
变速运动基本公式:
① v=v0+at 匀加速\减速运行
② s=v0t+½at² 位移
③ v²-v0²=2as
'''
# 初速度
v0 = 0
# 加减速度列表
a_list = [50, 65, 80]
# 时间
t = 0.2
# 初始位置
s = 0
# 向前滑动轨迹
forward_stacks = []
mid = distance * 3 / 5
while s < distance:
if s < mid:
a = a_list[random.randint(0, 2)]
else:
a = -a_list[random.randint(0, 2)]
v = v0
stack = v * t + 0.5 * a * (t ** 2)
# 每次拿到的位移
stack = round(stack)
s += stack
v0 = v + a * t
forward_stacks.append(stack)
# 往后返回20距离,因为之前distance向前多走了20
back_stacks = [-5, -5, -5, -5,]
return {'forward_stacks': forward_stacks, 'back_stacks': back_stacks}
if __name__ == '__main__':
try:
driver.get('https://account.cnblogs.com/signin')
# 隐式等待
driver.implicitly_wait(5)
# 步骤一:找到输入账户框
user_input = driver.find_element_by_id('LoginName')
# 步骤二:找到输入密码框
pwd_input = driver.find_element_by_id('Password')
user_input.send_keys('123456@qq.com')
time.sleep(1)
pwd_input.send_keys('123456')
# 步骤三:找到确认登录按钮,并点击
login_btn = driver.find_element_by_id('submitBtn')
time.sleep(1)
login_btn.click()
time.sleep(3)
# 步骤四: 拿到没有缺口的图片并截取
img1 = get_img1(driver)
# 步骤五: 拿到有缺口的图片并截取
img2 = get_img2(driver)
# 步骤六: 对比两张图片,获取滑动距离
distance = get_distance(img1, img2)
# 步骤七: 模拟人为滑动轨迹
stacks = get_stacks(distance)
# 步骤八: 根据滑动轨迹进行滑动
forward_stacks = stacks['forward_stacks']
back_stacks = stacks['back_stacks']
# 步骤九:找到滑动按钮,并点击与hole住
slider_btn = driver.find_element_by_class_name('geetest_slider_button')
time.sleep(0.2)
ActionChains(driver).click_and_hold(slider_btn).perform()
time.sleep(0.2)
# 步骤十:开始循环向前滑动
for forward_stack in forward_stacks:
ActionChains(driver).move_by_offset(xoffset=forward_stack, yoffset=0).perform()
time.sleep(0.1)
# 步骤十一:开始循环向后滑动20
for back_stack in back_stacks:
ActionChains(driver).move_by_offset(xoffset=back_stack, yoffset=0).perform()
time.sleep(0.1)
time.sleep(0.2)
# 步骤十二:为了防止极验检测到,再将滑块前后小浮动5位置,再释放
ActionChains(driver).move_by_offset(xoffset=5, yoffset=0).perform()
time.sleep(0.2)
ActionChains(driver).move_by_offset(xoffset=-5, yoffset=0).perform()
# 可能会出现识别不了,说图片被怪物吃了,上面模拟人的行为都不要了,拿到距离后,直接执行下面代码,一步滑到缺口处即可
# ActionChains(driver).move_by_offset(xoffset=distance, yoffset=0).perform()
ActionChains(driver).release().perform()
time.sleep(50)
finally:
driver.close()