社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

七步完美解决问题python爬虫极验滑动验证码问题

python • 5 年前 • 387 次点击  

滑动验证码的识别介绍

本节目标:

用程序识别极验滑动验证码的验证,包括分析识别思路、识别缺口位置、生成滑块拖动路径、模拟实现滑块拼合通过验证等步骤。

准备工作:

本次案例我们使用Python库是Selenium,浏览器为Chrome。请确保已安装Selenium库和ChromeDriver浏览器驱动。

了解极验滑动验证码:

极验滑动验证码官网为:http://www.geetest.com/

验证方式为拖动滑块拼合图像,若图像完全拼合,则验证成功,否则需要重新验证,如图所示:


接下来我们链接地址:https://account.geetest.com/login,打开极验的管理后台登录页面,完成自动化登录操作。

实现步骤:

① 初始化

初始化链接地址、创建模拟浏览器对象、设置登录账户和密码等信息。

EMAIL = '登录账户'PASSWORD = '登录密码'
class CrackGeetest(): def __init__(self): self.url = 'https://account.geetest.com/login' self.browser = webdriver.Chrome() #设置显示等待时间 self.wait = WebDriverWait(self.browser, 20) self.email = EMAIL self.password = PASSWORD
def crack(): pass
# 程序主入口if __name__ == '__main__': crack = CrackGeetest() crack.crack()

② 模拟登录填写,点开滑块验证

  • 在实例化CrackGeetest对象后调用crack()方法开始模拟登录验证...

  • 调用open()方法,打开登录界面,获取账户和密码输入框节点,完成账户和密码的输入。

  • 调用get_geetest_button()方法获取滑动验证按钮,并点击。

class CrackGeetest(): #...
def get_geetest_button(self): ''' 获取初始验证按钮,return:按钮对象 ''' button = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'geetest_radar_tip'))) return button
def open(self): ''' 打开网页输入用户名密码, return: None ''' self.browser.get(self.url) email = self.wait.until(EC.presence_of_element_located((By.ID, 'email'))) password = self.wait.until(EC.presence_of_element_located((By.ID, 'password'))) email.send_keys(self.email) password.send_keys(self.password)
def crack(self): # 输入用户名密码 self.open() # 点击验证按钮 button = self.get_geetest_button() button.click() #... #...

③ 获取并储存有无缺口的两张图片

  • 首先获取无缺口的验证图片,并保存到本地

  • 获取滑块对象,并执行点击,让浏览器中显示有缺口图片

  • 获取有缺口的验证图片,并保存到本地

def get_position(self): ''' 获取验证码位置, return: 验证码位置(元组) ''' 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): ''' 获取网页截图, 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 get_slider(self): ''' 获取滑块, return: 滑块对象 ''' slider = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'geetest_slider_button'))) return slider
def crack(self): #...
# 获取验证码图片 image1 = self.get_geetest_image('captcha1.png') # 点按呼出缺口 slider = self.get_slider() slider.click() # 获取带缺口的验证码图片 image2 = self.get_geetest_image('captcha2.png')
#...

④ 获取缺口位置

  • 对比两张图片的所有RBG像素点,得到不一样像素点的x值,即要移动的距离

BORDER = 6INIT_LEFT = 60
class CrackGeetest(): def get_gap(self, image1, image2): ''' 获取缺口偏移量, 参数:image1不带缺口图片、image2带缺口图片。返回偏移量 ''' left = 65 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: 像素是否相同 ''' # 取两个图片的像素点(R、G、B) pixel1 = image1.load()[x, y] pixel2 = image2.load()[x, y] threshold = 60 if abs(pixel1[0]-pixel2[0])and abs(pixel1[1]-pixel2[1])and abs(pixel1[2]-pixel2[2]) return True else: return False
def crack(self): #...
# 获取缺口位置 gap = self.get_gap(image1, image2) print('缺口位置', gap) # 减去缺口位移 gap -= BORDER

⑤ 获取移动轨迹

模拟人的行为习惯(先匀加速拖动后匀减速拖动),把需要拖动的总距离分成一段一段小的轨迹

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 = -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 crack(self): #...
# 获取移动轨迹 track = self.get_track(gap) print('滑动轨迹', 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()
def crack(self): #...
# 拖动滑块 self.move_to_gap(slider, track)
success = self.wait.until( EC.text_to_be_present_in_element((By.CLASS_NAME, 'geetest_success_radar_tip_content'), '验证成功')) print(success)

⑦ 完成登录

 def login(self): ''' 执行登录 return: None ''' submit = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'login-btn'))) submit.click() time.sleep(10) print('登录成功')
def crack(self): #...
# 失败后重试 if not success: self.crack() else: self.login()

*声明:本文于网络整理,版权归原作者所有,如来源信息有误或侵犯权益,请联系我们删除或授权事宜。

觉得不错,点个“在看”然后转发出去

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/48696
 
387 次点击