笔者是一名初入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),我们将立即处理。