原文:https://www.cnblogs.com/rrh4869/p/11192297.html
1.模拟登录的网站:
bilibili视频网:https://passport.bilibili.com/login
2. 开发环境
本项目需要用到
io
time
random
selenium
PIL
请安装对应版本的库如下,其他库均为标准库,无需安装 pip install pillow pip install selenium
3.项目流程介绍
- 初始化
- 请求bilibili的登录页面&模拟输入账号密码
- 有阴影拼图的验证码图片&获取验证码图片
- 比较两个验证码图片获取验证码滑块的偏移量
- 使用偏移值计算移动操作
- 操作滑块按钮,模拟拖动滑块做验证登录
5.bilibili模拟登陆-初始化和模拟输入账号密码
class Bilibili(object): def __init__(self): #创建浏览器对象 self.driver = webdriver.Chrome() #隐式等待 self.driver.implicitly_wait(3) self.url = 'https://passport.bilibili.com/login' #用户名 self.user = '' #密码 self.pwd = '' def close(self): ''' 关闭浏览器 ''' self.driver.quit() def input_user_pwd(self): ''' 输入用户名和密码 ''' #进入登陆页面 self.driver.get(self.url) #文本框输入用户名 tb_user = self.driver.find_element_by_id('login-username') tb_user.send_keys(self.user) #文本框输入密码 tb_pwd = self.driver.find_element_by_id('login-passwd') tb_pwd.send_keys(self.pwd)

6.有阴影拼图的验证码图片&获取验证码图片
def get_screenshot(self): ''' 获取屏幕截图 ''' screenshot = self.driver.get_screenshot_as_png() screenshot =Image.open(BytesIO(screenshot)) return screenshot def update_style(self): ''' 修改图片的style属性,显示无缺口的图片 ''' js = 'document.querySelectorAll("canvas")[3].style="display:block"' self.driver.execute_script(js) time.sleep(2) def get_position(self): ''' 获取截取验证码时的四条边 ''' #定位到登陆按钮 bt_login = self.driver.find_element_by_xpath('//a[@class="btn btn-login"]') #模拟点击 bt_login.click() time.sleep(2) #获取验证码图片对象 code_img = self.driver.find_element_by_xpath('//canvas[@class="geetest_canvas_slice geetest_absolute"]') time.sleep(2) location = code_img.location size = code_img.size #screenshot = self.get_screenshot() #print(screenshot.size) #计算图片截取区域(左,上,右,下,的坐标值)
left,top,right,buttom = location['x'],location['y'],location['x']+size['width'],location['y']+size['height'] return left,top,right,buttom def get_image(self): ''' 截取验证码图片 ''' #获取验证码位置 position = self.get_position() #从屏幕截图中抠出有缺口的验证码图片 captcha1 = self.get_screenshot().crop(position) #修改style属性,显示无缺口的验证码图片 self.update_style() #从屏幕截图中抠出无缺口的验证码图片 captcha2 = self.get_screenshot().crop(position) with open('captcha1.png','wb') as f1 ,open('captcha2.png','wb') as f2: captcha1.save(f1) captcha2.save(f2) return captcha1,captcha2

7. 比较两个验证码图片获取验证码滑块的偏移量
def is_pixel_equal(self,img1,img2,x,y): ''' 判断两张图片的同一像素点的RGB值是否相等 ''' pixel1,pixel2= img1.load()[x,y],img2.load()[x,y] #print(pixel1,pixel2) #设定一个比较基准 sub_index = 60 #比较 if abs(pixel1[0]-pixel2[0])< sub_index and abs(pixel1[1]-pixel2[1])< sub_index and abs(pixel1[2]-pixel2[2])< sub_index: return True else: return False def get_gap_offset(self,img1,img2): ''' 获取缺口的偏移量 ''' x = int(img1.size[0]/4.2) for i in range(x,img1.size[0]): for j in range(img1.size[1]): #两张图片对比,(i,j)像素点的RGB差距,过大则该x为偏移值 if not self.is_pixel_equal(img1,img2,i,j): x = i return x return x

8.使用偏移值计算移动操作(轨迹)
def get_track(self,offset): ''' 模拟人为拖动验证码滑块 ''' track = [] #滑块起始x坐标 current = 5 #变速临界值 border_point = int(offset*3/5) #设置时间间隔 t = 0.2 #设置初速度 offset +=4 v = 0 #循环直到滑动到偏移值时退出 while current < offset: #根据是否临界点改变运动状态 if current < border_point: #加速度 a = 1 else: a =-0.5 v0 = v v = v0 + a*t move = v0*t +0.5*a*t*t current += move track.append(round(move)) return track

9.操作滑块按钮,模拟拖动滑块做验证登录
def shake_mouse(self): """ 模拟人手释放鼠标抖动 :return: None """ ActionChains(self.driver).move_by_offset(xoffset=-2,yoffset=0).perform() ActionChains(self.driver).move_by_offset(xoffset=2,yoffset=0).perform() def operate_slider(self,track): ''' 拖动滑块 ''' #获取拖动按钮 back_tracks = [-1,-1,-2,-1] slider_bt = self.driver.find_element_by_xpath('//div[@class="geetest_slider_button"]') #点击拖动验证码的按钮不放 ActionChains(self.driver).click_and_hold(slider_bt).perform() #按正向轨迹移动 for i in track: ActionChains(self.driver).move_by_offset(xoffset=i,yoffset=0).perform() #先加速后减速效果也不是很好。 #每移动一次随机停顿0-1/100秒之间骗过了极验,通过率很高 time.sleep(random.random()/100) time.sleep(random.random()) #按逆向轨迹移动 for i in back_tracks: time.sleep(random.random()/100) ActionChains(self.driver).move_by_offset(xoffset=i,yoffset=0).perform() #模拟人手抖动 self.shake_mouse() time.sleep(random.random()) #松开滑块按钮 ActionChains(self.driver).release().perform() def do_captcha(self): ''' 实现处理验证码 ''' #有缺口,无缺口图片 img1,img2 = self.get_image() #比较两个验证码图片获取验证码滑块的偏移量 offset = self.get_gap_offset(img1,img2) print(offset) #使用偏移值计算移动操作 track = self.get_track(offset) #操作滑块按钮,模拟拖动滑块做验证登录 self.operate_slider(track) def login(self): ''' 实现主要的登陆逻辑 ''' #来到登陆界面并输入账号密码 self.input_user_pwd() #处理验证码 self.do_captcha() #关闭浏览器 self.close() def run(self): self.login() if __name__ == '__main__': bili =Bilibili() bili.run()
