Python selenium 模拟登录bilibili

Selenium 是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。

​ 在登录bilibili的时候,会有一个拖动图片的验证——极验验证码。我们用selenium在Chrome中打开bilibili的登录页面。然后填写登录账号和密码。再点击登录按钮,页面弹出极验验证码,通过js获取两张图片(一张完整的图片,一张有缺口的图片),这两张图片是用canvas画出来的。所有我们用toDataURL(“image/png”)方法拿到的是base64格式的图片。将这两张图片的用PIL中的Image来获转化之后的图片。比较两张图片的像素点,从而计算出拖动块需要移动的距离。

流程图

总体框架

class LoginBiliBili:def __init__(self, username, password):"""初始化数据:param username: bilibili账号:param password: 密码"""def open(self):"""打开浏览器, 进入登陆界面输入用户名, 密码点击登陆:return: None"""def get_geetest_image(self):"""获取极验验证码图片:return: c_image(王者验证图) ic_image(有缺失的验证图)"""def is_pixel_similar(self, c_image, ic_image, x, y):"""比较两张图片的像素点注意: 像素点比较是有偏差的, 需要允许一定范围的误差,我们可以设置一个阈值:param ic_image::param c_image::param x::param y::return: 当像素点不相同时, 返回 False"""def get_slice_gap(self, c_image, ic_image):"""获取缺口的偏移量通过比较两张图片的所有像素点, 获取两张图片是从哪里开始不同从而得到 移动块 要在 x 方向移动的距离:param c_image: 完整的图片:param ic_image: 有缺失的图片:return: 缺口的偏移量"""def drag_slider(self, gap):"""拖动滑块:param gap: 需要拖动的距离:return: None"""def login_success(self):"""判断是否登陆成功:return: 成功返回 True 失败返回False"""def login(self):"""开始:return: None"""if __name__ == '__main__':login = LoginBiliBili('*******', '******')login.login()

初始化数据方法

将一些初始化数据在__init__()函数中定义

def __init__(self, username, password):"""初始化数据:param username: bilibili账号:param password: 密码"""self.username = usernameself.password = password# 定义浏览器self.browser = webdriver.Chrome()# 定义显示等待self.wait = WebDriverWait(self.browser, 50)# bilibili登录urlself.url = 'https://passport.bilibili.com/login'

打开浏览器方法

此方法用来打开浏览器,在进入登陆页面之后,自动输入用户名,密码。以及点击的登录按钮

def open(self):"""打开浏览器, 进入登陆界面输入用户名, 密码点击登陆:return: None"""# 打开浏览器, 进入登陆界面self.browser.get(self.url)# 用户名输入框username_input_box = self.wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="login-username"]')))# 清空用户名输入框username_input_box.clear()# 将自己的用户名输入到用户名输入框username_input_box.send_keys(self.username)# 密码输入框password_input_box = self.wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="login-passwd"]')))# 清空密码输入框password_input_box.clear()# 将自己的密码输入到密码输入框password_input_box.send_keys(self.password)# 登录按钮login_button = self.wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="geetest-wrap"]/ul/li[5]/a[1]')))# 点击登录login_button.click()# 休眠, 让验证码图片加载出来time.sleep(2)

拿极验验证码图片方法

如何拿到极验验证码图片是我们进行模拟登录的关键一步,这里的极验验证码是由canvas绘制的两张图片,所有我们需要用js去获取图片。

def get_geetest_image(self):"""获取极验验证码图片:return: c_image(王者验证图) ic_image(有缺失的验证图)""""""完整的验证图页面源码:<canvas class="geetest_canvas_fullbg geetest_fade geetest_absolute" height="160" width="260" style="display: none;"></canvas>"""# 执行js 拿到canvas画布里面的图片数据js = 'return document.getElementsByClassName("geetest_canvas_fullbg")[0].toDataURL("image/png");'# 图片数据complete_img_data = self.browser.execute_script(js)# base64 编码的图片信息complete_img_base64 = complete_img_data.split(',')[1]# 转成bytes类型complete_img = base64.b64decode(complete_img_base64)# 加载图片 return 回去对比c_image = Image.open(BytesIO(complete_img))# c_image.show()# 保存图片 (可不必保存)c_image.save('c_image.png')"""有缺失的验证码图页面源码:<canvas class="geetest_canvas_bg geetest_absolute" height="160" width="260"></canvas>"""# 执行js 拿到canvas画布里的图片数据js = 'return document.getElementsByClassName("geetest_canvas_bg")[0].toDataURL("image/png");'# 图片数据incomplete_img_data = self.browser.execute_script(js)# base64 编码的图片信息incomplete_img_base64 = incomplete_img_data.split(',')[1]# 转为bytes类型incomplete_img = base64.b64decode(incomplete_img_base64)# 直接加载图片 return 回去对比ic_image = Image.open(BytesIO(incomplete_img))# ic_image.show()# 保存图片(可不必保存)ic_image.save('ic_image.png')return c_image, ic_image

# 对比像素点方法 和 获取移动距离方法

这两个方法我们要将它们联系起来,我们通过对比图片横向和纵向的像素点,来确定两张图片是从哪里开始不同的。当然,我们只需要得知水平方向哪里开始不同的(滑块只需要在水平方向移动)

def is_pixel_similar(self, c_image, ic_image, x, y):"""比较两张图片的像素点注意: 像素点比较是有偏差的, 需要允许一定范围的误差,我们可以设置一个阈值:param ic_image::param c_image::param x::param y::return: 当像素点不相同时, 返回 False"""# 获取两张图片执行位置的像素点c_pixel = c_image.load()[x, y]ic_pixel = ic_image.load()[x, y]# 阈值 允许误差threshold = 10# 对比if abs(c_pixel[0] - ic_pixel[0]) < threshold and \abs(c_pixel[1] - ic_pixel[1]) < threshold and \abs(c_pixel[2] - ic_pixel[2]) < threshold:return Truereturn Falsedef get_slice_gap(self, c_image, ic_image):"""获取缺口的偏移量通过比较两张图片的所有像素点, 获取两张图片是从哪里开始不同从而得到 移动块 要在 x 方向移动的距离:param c_image: 完整的图片:param ic_image: 有缺失的图片:return: 缺口的偏移量"""# ic_image.size:['width', 'height']for x in range(c_image.size[0]):for y in range(c_image.size[1]):if not self.is_pixel_similar(c_image, ic_image, x, y):# 移动块只在水平方向移动 只需返回 xreturn x

拖动滑块方法

然后就是拖动滑块了.

def drag_slider(self, gap):"""拖动滑块:param gap: 需要拖动的距离:return: None"""slider = self.wait.until(EC.presence_of_element_located((By.XPATH, '/html/body/div[2]/div[2]/div[6]/div/div[1]/div[2]/div[2]')))# 抓住滑块ActionChains(self.browser).click_and_hold(on_element=slider).perform()# 移动 只在水平方向上移动ActionChains(self.browser).move_by_offset(xoffset=gap, yoffset=0).perform()# 释放滑块ActionChains(self.browser).release().perform()

由于对比像素点有一定的误差,不一定会一次成功,所有我们会需要一个循环来进行多次验证,在判断成功登录之后,才结束进程.

判断是否登录

def login_success(self):"""判断是否登陆成功:return: 成功返回 True 失败返回False"""try:# 登录成功后 界面上会有一个消息按钮return bool(WebDriverWait(self.browser, 5).until(EC.presence_of_element_located((By.XPATH, '//a[@title="消息"]'))))except TimeoutException:return False

开始登录

def login(self):"""开始:return: None"""# 打开浏览器, 输入账号 密码, 点击登陆self.open()# 获取验证图 ic_image(有缺失的验证图) c_image(完整的验证图)c_image, ic_image = self.get_geetest_image()# 获取缺口的偏移量gap = self.get_slice_gap(c_image, ic_image)print(f'缺口的偏移量为:{gap}')# 拖动滑块# TODO 这边一直有一定的误差 暂时用测量工具解决self.drag_slider(gap-8)time.sleep(3)if self.login_success():print('登陆成功')else:self.login()

完整的代码

class LoginBiliBili:def __init__(self, username, password):"""初始化数据:param username: bilibili账号:param password: 密码"""self.username = usernameself.password = password# 定义浏览器self.browser = webdriver.Chrome()# 定义显示等待self.wait = WebDriverWait(self.browser, 50)# bilibili登录urlself.url = 'https://passport.bilibili.com/login'def open(self):"""打开浏览器, 进入登陆界面输入用户名, 密码点击登陆:return: None"""# 打开浏览器, 进入登陆界面self.browser.get(self.url)# 用户名输入框username_input_box = self.wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="login-username"]')))# 清空用户名输入框username_input_box.clear()# 将自己的用户名输入到用户名输入框username_input_box.send_keys(self.username)# 密码输入框password_input_box = self.wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="login-passwd"]')))# 清空密码输入框password_input_box.clear()# 将自己的密码输入到密码输入框password_input_box.send_keys(self.password)# 登录按钮login_button = self.wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="geetest-wrap"]/ul/li[5]/a[1]')))# 点击登录login_button.click()# 休眠, 让验证码图片加载出来time.sleep(2)def get_geetest_image(self):"""获取极验验证码图片:return: c_image(王者验证图) ic_image(有缺失的验证图)""""""完整的验证图页面源码:<canvas class="geetest_canvas_fullbg geetest_fade geetest_absolute" height="160" width="260" style="display: none;"></canvas>"""# 执行js 拿到canvas画布里面的图片数据js = 'return document.getElementsByClassName("geetest_canvas_fullbg")[0].toDataURL("image/png");'# 图片数据complete_img_data = self.browser.execute_script(js)# base64 编码的图片信息complete_img_base64 = complete_img_data.split(',')[1]# 转成bytes类型complete_img = base64.b64decode(complete_img_base64)# 加载图片 return 回去对比c_image = Image.open(BytesIO(complete_img))# c_image.show()# 保存图片 (可不必保存)c_image.save('c_image.png')"""有缺失的验证码图页面源码:<canvas class="geetest_canvas_bg geetest_absolute" height="160" width="260"></canvas>"""# 执行js 拿到canvas画布里的图片数据js = 'return document.getElementsByClassName("geetest_canvas_bg")[0].toDataURL("image/png");'# 图片数据incomplete_img_data = self.browser.execute_script(js)# base64 编码的图片信息incomplete_img_base64 = incomplete_img_data.split(',')[1]# 转为bytes类型incomplete_img = base64.b64decode(incomplete_img_base64)# 直接加载图片 return 回去对比ic_image = Image.open(BytesIO(incomplete_img))# ic_image.show()# 保存图片(可不必保存)ic_image.save('ic_image.png')return c_image, ic_imagedef is_pixel_similar(self, c_image, ic_image, x, y):"""比较两张图片的像素点注意: 像素点比较是有偏差的, 需要允许一定范围的误差,我们可以设置一个阈值:param ic_image::param c_image::param x::param y::return: 当像素点不相同时, 返回 False"""# 获取两张图片执行位置的像素点c_pixel = c_image.load()[x, y]ic_pixel = ic_image.load()[x, y]# 阈值 允许误差threshold = 10# 对比if abs(c_pixel[0] - ic_pixel[0]) < threshold and \abs(c_pixel[1] - ic_pixel[1]) < threshold and \abs(c_pixel[2] - ic_pixel[2]) < threshold:return Truereturn Falsedef get_slice_gap(self, c_image, ic_image):"""获取缺口的偏移量通过比较两张图片的所有像素点, 获取两张图片是从哪里开始不同从而得到 移动块 要在 x 方向移动的距离:param c_image: 完整的图片:param ic_image: 有缺失的图片:return: 缺口的偏移量"""# ic_image.size:['width', 'height']for x in range(c_image.size[0]):for y in range(c_image.size[1]):if not self.is_pixel_similar(c_image, ic_image, x, y):# 移动块只在水平方向移动 只需返回 xreturn xdef drag_slider(self, gap):"""拖动滑块:param gap: 需要拖动的距离:return: None"""slider = self.wait.until(EC.presence_of_element_located((By.XPATH, '/html/body/div[2]/div[2]/div[6]/div/div[1]/div[2]/div[2]')))# 抓住滑块ActionChains(self.browser).click_and_hold(on_element=slider).perform()# 移动 只在水平方向上移动ActionChains(self.browser).move_by_offset(xoffset=gap, yoffset=0).perform()# 释放滑块ActionChains(self.browser).release().perform()def login_success(self):"""判断是否登陆成功:return: 成功返回 True 失败返回False"""try:# 登录成功后 界面上会有一个消息按钮return bool(WebDriverWait(self.browser, 5).until(EC.presence_of_element_located((By.XPATH, '//a[@title="消息"]'))))except TimeoutException:return Falsedef login(self):"""开始:return: None"""# 打开浏览器, 输入账号 密码, 点击登陆self.open()# 获取验证图 ic_image(有缺失的验证图) c_image(完整的验证图)c_image, ic_image = self.get_geetest_image()# 获取缺口的偏移量gap = self.get_slice_gap(c_image, ic_image)print(f'缺口的偏移量为:{gap}')# 拖动滑块# TODO 这边一直有一定的误差 暂时用测量工具解决self.drag_slider(gap-8)time.sleep(3)if self.login_success():print('登陆成功')else:self.login()if __name__ == '__main__':login = LoginBiliBili('*******', '******')login.login()

Python selenium 模拟登录bilibili相关推荐

  1. python访问陌生人qq空间_使用Python+Selenium模拟登录QQ空间

    使用Python+Selenium模拟登录QQ空间 爬QQ空间之类的页面时大多需要进行登录,研究QQ登录规则的话,得分析大量Javascript的加密解密,这绝对能掉好几斤头发.而现在有了seleni ...

  2. Python selenium 模拟登录QQ空间

    下面文档的脚本执行,必须要下载 谷歌浏览器对应的驱动详细的流程时 selenium的使用流程a 环境的安装 b 谷歌浏览器驱动下载地址:http://chromedriver.storage.goog ...

  3. python+selenium获取cookie session_Python Selenium模拟登录成功后,使用此cookie、利用requests库进行get时,提示“非法登陆”。...

    一. 步骤概述 a. 模拟登录学校选课系统(使用Selenium库登陆http://xk.suibe.edu.cn/xsxk/login.xk) b. 取得cookie后传入requests的sess ...

  4. python爬虫-selenium模拟登录豆瓣获取cookies给requests使用

    1. selenium如何切换到iframe中操作 import time from selenium import webdriverurl = "https://www.douban.c ...

  5. selenium模拟登录豆瓣和qq空间

    selenium模拟登录豆瓣和qq空间 今天又重新学习了下selenium,模拟登录豆瓣,发现设置等待时间真的是很重要的一步,不然一直报错:selenium.common.exceptions.NoS ...

  6. 使用selenium模拟登录解决滑块验证问题

    本次主要是使用selenium模拟登录网页端的TX新闻,本来最开始是模拟请求的,但是某一天突然发现,部分账号需要经过滑块验证才能正常登录,如果还是模拟请求,需要的参数太多了,找的心累.不过好在TX的滑 ...

  7. 2021春项目需求记录 python实现模拟登录+爬取NASA Modis 上的产品数据

    python实现模拟登录+爬取Nasa Modis 上的产品数据 概述 需求分析 基本思路 代码 概述 3月的中旬时候参与了学校的一个大创项目,作为本科生,本人只是摸鱼打杂,负责了其中的一个功能模块: ...

  8. 越过验证码 selenium模拟登录B站项目实战(附源码)

    实战:selenium模拟登录B站 登录验证码处理 selenium 中的难点验证码破解因为确实没有很好的方式,一般都需要通过第三方平台实现破解,本案例中使用的是超级鹰平台(收费,大概1元30次,测试 ...

  9. python–爬虫–模拟登录全面介绍和简例–以抓取雅卓app为例

    转载请注明出处:python–爬虫–模拟登录全面介绍和简例–以抓取雅卓app为例 我们在前面的文章中已经学习了如果使用python进行数据抓取. 但我们常常会遇到一种场景,就是想要获取的页面内容或者接 ...

最新文章

  1. The current directory must be set to the ITT directory解决办法
  2. Locust接口性能测试
  3. 使用git将本地项目上传到github
  4. PHP-高并发和大流量的解决方案
  5. 可扩展的Web架构和分布式系统
  6. Nginx+PHP-FPM优化技巧总结(转发别人的,自己留着收藏个记录用)
  7. 你为什么不敢重构代码?听高手亲授秘笈!
  8. Solidworks如何在自定义的基准面上创建3D草图
  9. 2019118_四个化学数据分析(4)
  10. 【每日算法Day 87】今天我脱单了,所以大家不用做题了!
  11. 利用excel做简单的曲线拟合并生成公式
  12. xp查看计算机mac地址查询,如何查看mac地址 xp系统查看查询mac地址方法介绍
  13. 传奇开服教程——legend/blue引擎替换和登陆器生成教程
  14. 计算机一级c类题库及答案解析,全国计算机一级考试试题题库及答案
  15. astah——UML类图画法
  16. 什么是散列表(Hash Table)
  17. 如何将电脑上的音乐传到苹果手机上?电脑音乐导入苹果手机
  18. 微软surface屏幕测试软件,Soomal作品 - Microsoft 微软 Surface Go平板电脑屏幕测评报告 [Soomal]...
  19. 【引语练习题】Ask questions politely
  20. ECCV2022 | 生成对抗网络GAN论文汇总(图像转换-图像编辑-图像修复-少样本生成-3D等)...

热门文章

  1. 黑客攻防技术宝典(一)
  2. 【SAP Abap】SAP系统数据快速导出
  3. SAP FIORI专题之四:使用fiori element构建over page
  4. Mapper method ‘com.LH.mapper.EmployeeMapper.insertEmployee‘ has an unsupported return type: cla 报错
  5. 华恩JAVA班第22天
  6. 实例1QQ好友列表界面和九宫格
  7. Python求两数之和
  8. 亚马逊被关联?别怕有救
  9. 【php】php语法基础
  10. IDC评述网:2013年12月份中国域名服务商Top25