selenium之滑块验证码破解代码详解
PS:浏览器和电脑的缩放应该调为100%(Windows默认为125%),否则可能会导致获取局部图片时出现误差!
from selenium import webdriver from selenium.webdriver.common.action_chains import ActionChains from PIL import Image import time def get_snapshot(): "获取整个页面的快照,并返回图片对象" driver.save_screenshot('snapshot.png') pic_obj = Image.open('snapshot.png') return pic_obj def get_image(): # 获取滑块验证码图片所在div的元素对象 element = driver.find_element_by_xpath('//div[@class="geetest_slicebg geetest_absolute"]') # 计算滑块验证码部分截图的坐标 left = element.location['x'] top = element.location['y'] right = left + element.size['width'] bottom = top + element.size['height'] # 先获取整个界面截图的对象 pic_obj = get_snapshot() # 获取滑块验证码部分截图对象 part_pic_obj = pic_obj.crop((left, top, right, bottom)) return part_pic_obj def get_distance(image1, image2): ''' 拿到滑动验证码需要移动的距离 :param image1:没有缺口的图片对象 :param image2:带缺口的图片对象 :return:需要移动的距离 ''' # 从图像的左侧60像素开始匹配,把填充的那部分去掉,不比较,避免干扰。 left = 60 for i in range(left, image1.size[0]): # 图像的宽 for j in range(image1.size[1]): # 图像的高 rgb1 = image1.load()[i, j] rgb2 = image2.load()[i, j] res1 = abs(rgb1[0] - rgb2[0]) res2 = abs(rgb1[1] - rgb2[1]) res3 = abs(rgb1[2] - rgb2[2]) # 自定义容差为60定义为缺口 if res1 >= 60 and res2 >= 60 and res3 >= 60: return i - 7 # 误差大概是7 return left def get_tracks(distance): ''' 拿到移动轨迹,模仿人的滑动行为,先匀加速后匀减速 匀变速运动基本公式: ①v=v0+at ②s=v0t+½at² ③v²-v0²=2as :param distance: 需要移动的距离 :return: 存放每0.2秒移动的距离 ''' # 初速度 v = 0 # 单位时间为0.2s来统计轨迹,轨迹即0.2内的位移 t = 0.2 # 位移/轨迹列表,列表内的一个元素代表0.2s的位移 tracks = [] # 当前的位移 current = 0 # 到达mid值开始减速 mid = distance * 4 / 5 while current < distance: if current < mid: # 加速度越小,单位时间的位移越小,模拟的轨迹就越多越详细 a = 2 else: a = -3 # 初速度 v0 = v # 0.2秒时间内的位移 s = v0 * t + 0.5 * a * (t ** 2) # 当前的位置 current += s # 添加到轨迹列表 tracks.append(round(s)) # 速度已经达到v,该速度作为下次的初速度 v = v0 + a * t return tracks if __name__ == '__main__': try: driver = webdriver.Chrome() driver.get('https://account.ch.com/NonRegistrations-Regist') driver.maximize_window() driver.find_element_by_name('phoneNumberInput').send_keys('15216122411') # 单击,让滑块验证码的图片显示 getDynamicPwd = driver.find_element_by_xpath('//a[@id="getDynamicPwd"]') ActionChains(driver).move_to_element(getDynamicPwd).move_by_offset(5, 0).click().perform() # driver.find_element_by_xpath('//a[@id="getDynamicPwd"]').click() # driver.execute_script('document.getElementById("getDynamicPwd").click()') # driver.find_element_by_id('getDynamicPwd').click() time.sleep(2) # 沉睡两秒,加载滑块验证码 # 获取有缺口的滑块验证局部截图 image1 = get_image() image1.save('imag1.png') # 获取局部截图 # 获取没有缺口的图片 driver.execute_script('document.getElementsByClassName("geetest_canvas_fullbg")[0].style="display:block"') image2 = get_image() image2.save('imag2.png') # 获取局部截图 distance = get_distance(image1, image2) # 获取滑块 huakuai = driver.find_element_by_xpath('//div[@class="geetest_slider_button"]') # 拉动滑块开始执行 ActionChains(driver).click_and_hold(on_element=huakuai).perform() ActionChains(driver).move_by_offset(xoffset=distance * 0.5, yoffset=0).perform() # 闪现50% # 模拟人的行为习惯(先匀加速拖动后匀减速拖动),把需要拖动的总距离分成一段一段小的轨迹 tracks = get_tracks(distance * 0.5) # 剩下的50%在模拟移动 for x in tracks: ActionChains(driver).move_by_offset(xoffset=x, yoffset=0).perform() else: ActionChains(driver).move_by_offset(xoffset=3, yoffset=0).perform() # 先移过一点 ActionChains(driver).move_by_offset(xoffset=-3, yoffset=0).perform() # 再退回来,看上去更像人为 # 0.5s释放鼠标 time.sleep(0.5) ActionChains(driver).release().perform() except Exception as error: print(error) driver.close()
天青色等烟雨而我在等你!