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. BZOJ 2456 mode
  2. Zuul:Pre和Post过滤器(下)
  3. 【CodeForces - 514D】R2D2 and Droid Army(二分+滑动窗口ST表,或 尺取+单调队列或STLmultiset)
  4. vue if判断_vue循环判断
  5. 实战 | Vue + Element UI 页面创建
  6. html页面锁屏,锁屏页面.html
  7. UGUI 与 Spine 的完美结合
  8. redis sentinel集群与spring集成
  9. 打鱼晒网c语言用switch语句,三天打鱼两天晒网题目的C++源代码.docx
  10. 英语口语360之每日二十个英语单词
  11. 启用计算机的快捷键,电脑开机启动项选择快捷键大全
  12. c语言分解质因数法求最大公约数,最大公约数求法大全
  13. diskgenius克隆硬盘无法启动_用diskgenius成功拷出故障硬盘数据
  14. 51单片机实验——模拟三台机器故障检测与指示系统
  15. so链接及动态加载原理分析
  16. com.android.dazhihui,大智慧
  17. [转载]关于中文乱码问题的一些解决方案和经验
  18. JavaEE学习日志(七十三): 黑马商城项目(六)
  19. 数据科学与机器学习案例之客户的信用风险与预测
  20. Windows Thin PC体验 语言包更改(win 7 included)

热门文章

  1. flutter permission动态权限申请以及IOS端权限问题审核被拒处理
  2. 虫师 python_python学习虫师笔记 (一)
  3. Item 13: Prefer const_iterators to iterators.
  4. 轻易成就难事的 “ 美好心灵 ” 之力
  5. ffmpeg 视频倍速播放 和 慢速播放
  6. Ubuntu下视频播放加速软件SMPlyer
  7. 正交,独立,相关及之间的关系
  8. 签名签名签名签名签名签名签名
  9. Elasticsearch7.3文档管理
  10. IntelliJ IDEA LicenseServer激活及使用