通过selenium突破极验验证实现登录

发表于:2019-4-01 13:15

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:小郭pp    来源:掘金

  笔者是一名初入Python爬虫的小白,通过书籍(静觅大神出的书籍)的方式学了下突破验证的方式实现模拟登录有此类型的应用的知识。该方法不涉及任何商业关系,如果有违规行为麻烦联系下笔者
  实现的步骤分为3步:
  1.使应用出现验证的完整图片和带有缺口的图片
  2.识别缺口的位置
  3.模拟拖动滑块至缺口处,完成验证
  引入相关的库
   from selenium import webdriver;
  from selenium.webdriver.support.wait import WebDriverWait;
  from selenium.webdriver.support import expected_conditions as EC;
  from selenium.webdriver.common.by import By;
  from selenium.webdriver import ActionChains;
  import time;
  from PIL import Image;
  from io import BytesIO;
  我们定义一个类来实现相关的操作并且定义一些配置
   EMAIL='xxx'  #账号
  PASSWORD='xxx'  #密码(只是简单的处理)
  BORDER=6; #开始滑动的小块与左边缘的距离
  INIT_LEFT=60; #开始从X轴方向即x=60开始检测缺口的位置
  
    class GrackGeetest(object):
  def __init__(self):
  #这边我们开始定义一些相关的参数信息(我们用登录极验官网来做例子,其它的方式类似)
  self.url='https://auth.geetest.com/login/';
  self.browser=webdriver.Chrome();
  self.wait=WebDriverWait(self.browser,20);
  self.email=EMAIL;
  self.password=PASSWORD;
  #实现步骤1相关方法:
  def getGeetestButton(self):
  #获取点击可以使现验证图出现的按钮节点元素并返回
  button=self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME,'geetest_radar_tip')));
  return button;
  #获取验证图在网页中的位置并以元组的方式返回
  def getImagePosition(self):
  geetestImage=self.wait.until(EC.presence_of_element_located((By.CLASS_NAME,'geetest_canvas_img')));
  time.sleep(2);
  location=geetestImage.location;
  size=geetestImage.size;
  top,bottom,left,right=location['y'],location['y']+size['height'],location['x'],location['x']+size['width'];
  return (top,bottom,left,right);
  #截取当前页面
  def getChromePage(self):
  pageShot=self.browser.get_screenshot_as_png();
  pageShot=Image.open(BytesIO(pageShot));
  return pageShot;
  #从网页中截取该验证图片并返回
  def getGeetestImage(self,name='geetest.png'):
  top,bottom,left,right=self.getImagePosition();
  #截取当前页面的图片
  pageShot=self.getChromePage();
  #截取其中出现的验证图的位置
  captchaImage=pageShot.crop((left,top,right,bottom));
  captchaImage.save(name);#保存到当前的文件夹中
  return captchaImage;
  #实现步骤2相关方法:识别缺口位置
  def getSlider(self):
  #获取可拖动的滑块对象
  slider=self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME,'geetest_slider_button')));
  return slider;
  #通过对比2张图的像素点的差距得出缺口位置
  def getGap(self,image1,image2):
  left=60;
  #size[0]->width,size[1]->height
  for i in range(left,image1.size[0]):
  for j in range(image1.size[1]):
  if not self.isPixelEqual(image1,image2,i,j):
  #因为小滑块和缺口是同一条水平线上的所以就只取x轴方向上的值
  left=i;
  return left;
  return left;
  def isPixelEqual(self,image1,image2,x,y):
  #判断2个像素是否相同
  pixel1=image1.load()[x,y]; #pixel1,pixel2为rgb值,是一个元组
  pixel2=image2.load()[x,y];
  #阀值当超出这个阀值的时候则证明这2个像素点不匹配,为缺口的左上角的像素点
  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;
  #步骤三相关方法:最关键的一步也是突破极验验证机器学习算法的一步
  #采用物理中物体的分阶段改变加速度的方式,这里采用先加速后减速的方式
  #公式 x=v0*t+1/2*a*t*t  v=v0+a*t
  def getTrack(self,distance):
  #distance偏移量
  #移动轨迹
  tranck=[];
  #当前位移
  current=0;
  #开始减速的阀值
  mid=distance*4/5;
  #计算间隔
  t=0.2;
  #初速度
  v=0;
  while current<distance:
  if current<mid:
  a=2;
  else:
  #开始减速
  a=-3;
  #初速度
  v0=v;
  #当前速度
  v=v0+a*t;
  #位移
  move=v0*t+1/2*a*t*t;
  #当前位移
  current+=move;
  #加入轨迹
  track.append(round(move));
  return track;
  #按照运动轨迹移动滑块
  def moveToGap(self,slider,tracks):
  #拖动滑块到缺口处
  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.5);
  ActionChains(self.browser).release().perform();
  #最后模拟点击登录应用就行了
  def login(self):
  button=self.wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,'#base > div.content-outter > div > div > div:nth-child(3) > div > form > div:nth-child(5) > div > button')));
  button.click();
  time.sleep(10);
  #接下来直接实现通过一个方法将这整个过程连接起来
  def sendUserAndPassword(self):
  self.browser.get(self.url);
  #通过类选择器,我是直接在浏览器那边复制过来的,所以比较长,可以通过其它方式得到该元素(右键那个网页元素就有一些选择可以看看哈)
  email=self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'#base > div.content-outter > div > div > div:nth-child(3) > div > form > div:nth-child(1) > div > div.ivu-input-wrapper.ivu-input-type.ivu-input-group.ivu-input-group-with-prepend > input')));
  password=self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'#base > div.content-outter > div > div > div:nth-child(3) > div > form > div:nth-child(2) > div > div.ivu-input-wrapper.ivu-input-type.ivu-input-group.ivu-input-group-with-prepend > input')));
  email.send_keys(self.email);
  password.send_keys(self.password);
  def doVerifyLogin(self):
  #步骤1:
  #输入账号密码
  self.sendUserAndPassword();
  #点击验证按钮
  verifyButton=self.getGeetestButton();
  verifyButton.click();
  #开始获取2张验证图
  image1=self.getGeetestImage('geetest1.png');
  #点击小滑块得到有缺口的验证图
  slider=self.getSlider();
  slider.click();
  #获取带缺口的验证图
  image2=self.getGeetestImage('geetest2.png');
  #步骤2:
  #获取缺口位置
  gap=self.getGap(image1,image2);
  #缺口的位置需要减去那个小滑块与左边那一小段距离
  gap-=BORDER;
  #步骤3:
  #移动轨迹
  track=self.getTrack();
  #拖动滑块
  self.moveToGap(slider,track);
  #最后判断是否成功了,不成功就重新操作这一过程
  try:
  success = self.wait.until(
  EC.text_to_be_present_in_element((By.CLASS_NAME, 'geetest_success_radar_tip_content'), '验证成功'))
  print(success)
  # 失败后重试
  if not success:
  self.doVerifyLogin()
  else:
  self.login()
  except:
  self.doVerifyLogin();
  if __name__ == '__main__':
  crack = GrackGeetest();
  crack.doVerifyLogin();
    
  以上就是完整的代码了,同时需要安装ChromeDriver,安装的具体过程找下搜索引擎问问
  
     上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号