本文是使用极验滑动验证码的官网做的实验,没有账号的可以先注册一个账号 ,地址 :https://account.geetest.com/login
- 安装环境
- chromedriver 下载地址 可以根据自己chrome版本和系统自行下载
地址:http://chromedriver.storage.googleapis.com/index.html
查看chrome版本 和下载chromedriver页面:
将解压好的文件放入/usr/local/bin目录中,由于mac的很多目录都是隐藏的,所以我们按快捷键command+shift+g,在弹出的窗口输入/usr/local/bin,
就可以打开这个目录,接着将解压好的驱动放入此目录即可。
安装 selenium -
pip install selenium
- 安装 PIL 图片处理
当我们输入pip insall PIL时候会发现错误,没有这个模块。因为这个模块安装是以前版本,在命令行输入 pip install pillow
pip install pillow
- 测试
打开小黑窗
from selenium import webdriver from PIL import Image browser = webdriver.Chrome() browser.get("http://www.baidu.com")
得到以下结果证明环境没问题 接下来开始写代码咯
- chromedriver 下载地址 可以根据自己chrome版本和系统自行下载
写代码:
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.wait import WebDriverWait import time from io import BytesIO from PIL import Image from selenium.webdriver import ActionChains from selenium.common.exceptions import TimeoutException import random EMAIL = \'@qq.com\' PASSWORD = \'密码\' class CrackGeetest(): """ 初始化 """ def __init__(self): self.url = \'https://account.geetest.com/login\' self.browser = webdriver.Chrome() self.wait = WebDriverWait(self.browser, 5) self.email = EMAIL self.password = PASSWORD def __del__(self): self.browser.close() def open(self): """ 输入用户及密码 """ self.browser.get(self.url) email_xpath = \'//*[@id="base"]/div[2]/div/div[2]/div[3]/div/form/div[1]/div/div/input\' email = self.wait.until(EC.presence_of_element_located((By.XPATH, email_xpath))) password_xpath = \'//*[@id="base"]/div[2]/div/div[2]/div[3]/div/form/div[2]/div/div[1]/input\' password = self.wait.until(EC.presence_of_element_located((By.XPATH, password_xpath))) email.send_keys(self.email) password.send_keys(self.password) def get_geetest_button(self): """ 获取初始验证按钮 返回按钮对象 """ button = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, \'geetest_radar_tip\'))) return button def get_position(self): """ 获取验证码位置-为截取验证码准备 返回验证码位置元组 """ img = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME, \'geetest_canvas_img\'))) time.sleep(2) 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) def get_screenshot(self): """[summary] 获取网页截图 """ screenshot = self.browser.get_screenshot_as_png() screenshot = Image.open(BytesIO(screenshot)) return screenshot def get_geetest_image(self, name=\'captcha.png\'): """ 获取验证码图片 返回图片对象 """ top, bottom, left, right = self.get_position() screenshot = self.get_screenshot() # 通过验证码图片的位置从网页截图上截取验证码 captcha = screenshot.crop((left, top, right, bottom)) captcha.save(name) return captcha def get_slider(self): """ 获取滑块对象 """ slider = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, \'geetest_slider_button\'))) return slider def get_track(self, distance): """ 根据偏移量获取移动轨迹 Arguments: distance {[type]} -- 偏移量 """ # 移动轨迹 track = [] # 当前位移 current = 0 # 减速阀值 mid = distance * 7 / 10 # 计算间隔 t = 0.15 # 初速度 v = 0 while current < distance: if current < mid: # 加速度为正 a = 2.1 else: # 加速度为负 a = -4.8 # 初速度v0 v0 = v # 当前速度 v = v0 + at v = v0 + a * t # 移动距离 x = v0t + 1/2*a*t*t move = v0 * t + 1 / 2 * a * t * t # 当前位移 current += move # 加入轨迹 track.append(round(move, 2)) return track def move_to_gap(self, slider, tracks): """[summary] 拖动滑块到缺口处 动作: 点击且不释放鼠标-拖拽图片到缺口-释放鼠标 Arguments: slider {[type]} -- 滑块 tracks {[type]} -- 轨迹 """ # 点击并按住滑块 ActionChains(self.browser).click_and_hold(slider).perform() # 移动 for x in tracks: ActionChains(self.browser).move_by_offset(xoffset=x, yoffset=0).perform() time.sleep(0.1) # 释放滑块 ActionChains(self.browser).release().perform() def login(self): """[summary] 登录 """ submit = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, \'login-btn\'))) submit.click() time.sleep(1) print(\'登录成功\') def is_try_again(self): """[summary] 判断是否能够点击重试 """ button_text = self.browser.find_element_by_class_name(\'geetest_radar_tip_content\') text = button_text.text if text == \'尝试过多\': button = self.browser.find_element_by_class_name(\'geetest_reset_tip_content\') button.click() def is_success(self): """[summary] 判断是否成功 """ button_text2 = self.browser.find_element_by_class_name(\'geetest_success_radar_tip_content\') text2 = button_text2.text if text2 == \'验证成功\': return 1 return 0 def for_move(self, x_temp): """[summary] 循环拖动 """ flag = 0 for i in range(0, 7): gap = random.randint(16, 20) * i + x_temp if gap < 40: continue print(\'预估计缺口位置: \', gap) self.is_try_again() slider = self.get_slider() track = self.get_track(gap) print(\'滑动轨迹: \', track) # 拖动滑块 self.move_to_gap(slider, track) time.sleep(3) if self.is_success(): flag = 1 break return flag def crack(self): """[summary] 验证 """ try: # 输入用户和密码 self.open() time.sleep(2) # 点击验证按钮 button = self.get_geetest_button() button.click() # 获取验证码图片 image1 = self.get_geetest_image(\'captcha1.png\') flag = 0 while 1: temp = random.randint(0, 2) # 将轨迹划分为2, 则有1/2的几率 if temp == 0: print(\'预估左1/2: \') flag = self.for_move(30) else: print(\'预估右1/2: \') flag = self.for_move(120) if flag == 1: break except TimeoutException as e: self.crack() # 成功,登录 self.login() time.sleep(10) if __name__ == "__main__": crack = CrackGeetest() crack.crack()