思路

  1. 输入用户名密码点击登陆
  2. 获取验证码的原始图片与有缺口的图片
  3. 找出两张图片的缺口起始处
  4. 拖动碎片

功能代码段

# 使用到的库
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
from PIL import Image
import time
import base64
username = '用户名'
password = '密码'
# 放在外面的原因是如果再类的内部初始化,则程序结束后浏览器会自动退出
driver = webdriver.Chrome()

初始化相关参数

	# 初始化相关参数
def __init__(self):
self.url = 'https://passport.bilibili.com/login'
self.browser = driver
self.wait = WebDriverWait(self.browser, 20)
self.name = username
self.pw = password

获取按钮、输入框、碎片拖动按钮对象

	def get_login_button(self):
"""
获取初始登录按钮
:return: 按钮对象
"""
button = self.wait.until(
EC.presence_of_element_located((By.XPATH, "//a[contains(@class,'btn') and contains(@class, 'btn-login')]")))
return button def get_slider_button(self):
"""
获取拖动碎片的地方
:return: 拖动对象
"""
sliderbutton = self.wait.until(EC.presence_of_element_located((By.XPATH, "//div[@class='geetest_slider_button']")))
return sliderbutton def get_login_input(self):
"""
获取登陆输入框(用户名/密码)
:return: 输入框对象
"""
user_login = self.wait.until(EC.presence_of_element_located((By.XPATH, "//input[@id='login-username']")))
pw_login = self.wait.until(EC.presence_of_element_located((By.XPATH, "//input[@id='login-passwd']")))
return user_login, pw_login

获取带有碎片的图片和完整图片

    def save_pic(self, data, filename):
"""
解码获取到的base64再写入到文件中,保存图片
:return:
"""
data = data.split(',')[1]
data = base64.b64decode(data)
with open(filename, 'wb') as f:
f.write(data) def get_pic(self):
"""
获取无缺口图片和有缺口图片
:return: 图片对象
"""
picName = ['full.png', 'slice.png']
# 图片对象的class
className = ['geetest_canvas_fullbg', 'geetest_canvas_bg']
# canvas标签中的图片通过js代码获取base64编码,然后再通过解码,将其写入文件才能获取到
for i in range(len(className)):
js = "var change = document.getElementsByClassName('"+className[i]\
+ "'); return change[0].toDataURL('image/png');"
im_info = self.browser.execute_script(js)
self.save_pic(im_info, picName[i])

判断像素点是否相同

    def is_pixel_equal(self, image1, image2, x, y):
"""
判断两个像素点是否是相同
:param image1: 不带缺口图片
:param image2: 带缺口图片
:param x: 像素点的x坐标
:param y: 像素点的y坐标
:return:
"""
pixel1 = image1.load()[x, y]
pixel2 = image2.load()[x, y]
threshold = 40
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

获取需要移动的距离

    def get_gap(self, image1, image2):
"""
获取缺口偏移量
:param image1: 不带缺口图片
:param image2: 带缺口图片
:return:
"""
# 这个可以自行操作一下,如果发现碎片对不准,可以调整
left = 10
for i in range(left, image1.size[0]):
for j in range(image1.size[1]):
if not self.is_pixel_equal(image1, image2, i, j):
left = i
return left
return left

变速运动拖动碎片,否则容易被看出来是机器执行

    def get_track(self, distance):
"""
根据偏移量获取移动轨迹
:param self:
:param distance: 偏移量
:return: 移动轨迹
"""
# 移动轨迹
track = []
# 当前位移
current = 0
# 对的不一定很准确,所以自行调整一下distance
distance = distance - 9
# 减速阈值 -> 也就是加速到什么位置的时候开始减速
mid = distance * 4 / 5
# 计算间隔
t = 0.2
# 初速度
v = 0 while current < distance:
if current < mid:
# 加速度为正2
a = 2
else:
# 加速度为负3
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 move_to_gap(self, slider, tracks, browser):
"""
拖动滑块到缺口处
:param self:
:param slider: 滑块
:param tracks: 轨迹
:return:
"""
# click_and_hold()点击鼠标左键,不松开
ActionChains(self.browser).click_and_hold(slider).perform()
for x in tracks:
# move_by_offset()鼠标从当前位置移动到某个坐标
ActionChains(self.browser).move_by_offset(xoffset=x, yoffset=0).perform()
time.sleep(0.5)
# release()在某个元素位置松开鼠标左键
ActionChains(self.browser).release().perform()

配置执行

    def test(self):
# 输入用户名和密码
self.browser.get(self.url)
user_login, pw_login = self.get_login_input()
user_login.send_keys(self.name)
pw_login.send_keys(self.pw)
# 点击按钮对象
button = self.get_login_button()
button.click()
# 这里设置等待是为了使得滑动验证码能出现,之后才能通过toDataURL获取
time.sleep(3)
self.get_pic()
image1 = Image.open('full.png')
image2 = Image.open('slice.png')
left = self.get_gap(image1, image2)
track = self.get_track(left)
slider = self.get_slider_button()
self.move_to_gap(slider, track, self.browser)

完整代码

TIP

如果出现碎片移动存在一定对不准的情况,可以自行调整一下left和distance的值。

from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
from PIL import Image
import time
import base64
username = '用户名'
password = '密码'
driver = webdriver.Chrome() class Start:
def __init__(self):
self.url = 'https://passport.bilibili.com/login'
self.browser = driver
self.wait = WebDriverWait(self.browser, 20)
self.name = username
self.pw = password def get_login_button(self):
"""
获取初始登录按钮
:return: 按钮对象
"""
button = self.wait.until(
EC.presence_of_element_located((By.XPATH, "//a[contains(@class,'btn') and contains(@class, 'btn-login')]")))
return button def get_slider_button(self):
"""
获取拖动碎片的地方
:return: 拖动对象
"""
sliderbutton = self.wait.until(EC.presence_of_element_located((By.XPATH, "//div[@class='geetest_slider_button']")))
return sliderbutton def get_login_input(self):
"""
获取登陆输入框(用户名/密码)
:return: 输入框对象
"""
user_login = self.wait.until(EC.presence_of_element_located((By.XPATH, "//input[@id='login-username']")))
pw_login = self.wait.until(EC.presence_of_element_located((By.XPATH, "//input[@id='login-passwd']")))
return user_login, pw_login def save_pic(self, data, filename):
"""
解码获取到的base64再写入到文件中,保存图片
:return:
"""
data = data.split(',')[1]
data = base64.b64decode(data)
with open(filename, 'wb') as f:
f.write(data) def get_pic(self):
"""
获取无缺口图片和有缺口图片
:return: 图片对象
"""
# 图片对象的类名
# 首先需要这个东西已经出现了,我们才能去执行相关的js代码
picName = ['full.png', 'slice.png']
className = ['geetest_canvas_fullbg', 'geetest_canvas_bg']
# canvas标签中的图片通过js代码获取base64编码
for i in range(len(className)):
js = "var change = document.getElementsByClassName('"+className[i]\
+ "'); return change[0].toDataURL('image/png');"
im_info = self.browser.execute_script(js)
self.save_pic(im_info, picName[i]) def is_pixel_equal(self, image1, image2, x, y):
"""
判断两个像素点是否是相同
:param image1: 不带缺口图片
:param image2: 带缺口图片
:param x: 像素点的x坐标
:param y: 像素点的y坐标
:return:
"""
pixel1 = image1.load()[x, y]
pixel2 = image2.load()[x, y]
threshold = 40
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 def get_gap(self, image1, image2):
"""
获取缺口偏移量
:param image1: 不带缺口图片
:param image2: 带缺口图片
:return:
"""
# 这个可以自行操作一下,如果发现碎片对不准,可以调整
left = 10
for i in range(left, image1.size[0]):
for j in range(image1.size[1]):
if not self.is_pixel_equal(image1, image2, i, j):
left = i
return left
return left def get_track(self, distance):
"""
根据偏移量获取移动轨迹
:param self:
:param distance: 偏移量
:return: 移动轨迹
"""
# 移动轨迹
track = []
# 当前位移
current = 0
# 因为老对不的不准确,所以自行调整一下distance
distance = distance - 9
# 减速阈值 -> 也就是加速到什么位置的时候开始减速
mid = distance * 4 / 5
# 计算间隔
t = 0.2
# 初速度
v = 0 while current < distance:
if current < mid:
# 加速度为正2
a = 2
else:
# 加速度为负3
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 test(self):
# 输入用户名和密码
self.browser.get(self.url)
user_login, pw_login = self.get_login_input()
user_login.send_keys(self.name)
pw_login.send_keys(self.pw)
# 点击按钮对象
button = self.get_login_button()
button.click()
# 保存图片
time.sleep(3)
self.get_pic()
image1 = Image.open('full.png')
image2 = Image.open('slice.png')
left = self.get_gap(image1, image2)
track = self.get_track(left)
slider = self.get_slider_button()
self.move_to_gap(slider, track, self.browser) def move_to_gap(self, slider, tracks, browser):
"""
拖动滑块到缺口处
:param self:
:param slider: 滑块
:param tracks: 轨迹
:return:
"""
# click_and_hold()点击鼠标左键,不松开
ActionChains(self.browser).click_and_hold(slider).perform()
for x in tracks:
# move_by_offset()鼠标从当前位置移动到某个坐标
ActionChains(self.browser).move_by_offset(xoffset=x, yoffset=0).perform()
time.sleep(0.5)
# release()在某个元素位置松开鼠标左键
ActionChains(self.browser).release().perform() Start().test()

使用python - selenium模拟登陆b站的更多相关文章

  1. python selenium模拟登陆163邮箱。

    selenium是可以模拟浏览器操作. 有些爬虫是异步加载的,通过爬取网页源码是得不到需要的内容.所以可以模拟浏览器去登陆该网站进行爬取操作. 需要安装selenium通过pip install xx ...

  2. python selenium模拟登陆qq空间

    不多说.直接上代码 from selenium import webdriver driver = webdriver.Chrome() driver.get('http://qzone.qq.com ...

  3. python selenium 模拟登陆百度账号

    代码: from selenium import webdriver url = 'https://passport.baidu.com/v2/?login' username = 'your_use ...

  4. python+selenium 模拟登陆,自动下单

    目前写的实在太粗糙,留着,以后来写上

  5. Python实现模拟登陆

    大家经常会用Python进行数据挖掘的说,但是有些网站是需要登陆才能看到内容的,那怎么用Python实现模拟登陆呢?其实网路上关于这方面的描述很多,不过前些日子遇到了一个需要cookie才能登陆的网站 ...

  6. 【小白学爬虫连载(10)】–如何用Python实现模拟登陆网站

    Python如何实现模拟登陆爬取Python实现模拟登陆的方式简单来说有三种:一.采用post请求提交表单的方式实现.二.利用浏览器登陆网站记录登陆成功后的cookies,采用get的请求方式,传入c ...

  7. python爬虫模拟登陆

    python爬虫模拟登陆 学习了:https://www.cnblogs.com/chenxiaohan/p/7654667.html  用的这个 学习了:https://www.cnblogs.co ...

  8. Selenium模拟登陆百度贴吧

    Selenium模拟登陆百度贴吧 from selenium import webdriver from time import sleep from selenium.webdriver.commo ...

  9. 使用Python+Selenium模拟登录QQ空间

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

随机推荐

  1. display:none和visibility:hidden两者的区别

    display与元素的隐藏 如果给一个元素设置了display: none,那么该元素以及它的所有后代元素都会隐藏,它是前端开发人员使用频率最高的一种隐藏方式.隐藏后的元素无法点击,无法使用屏幕阅读器 ...

  2. docker进阶之路-基础篇 | 一:环境搭建

    转载请注明作者及出处: 作者:银河架构师 原文链接:https://www.cnblogs.com/luas/p/12061747.html 一.准备工作 查看内核 Docker 要求 CentOS ...

  3. textarea增加字数监听且高度自适应(兼容IE8)

    1.封装方法: var textareaListener = { /*事件监听器兼容 * *attachEvent——兼容:IE7.IE8:不兼容firefox.chrome.IE9.IE10.IE1 ...

  4. centos7 php(mariadb)安装pdo

    环境:centos7+php5.4.16+mariadb5.5.52 在centos7环境下安装PDO,安装的时候都是自己分开安装的,先装的PHP(httpd)后装的mariadb. 数据库安装完成后 ...

  5. JS---offset系列和scroll系列

    元素的样式属性是无法直接通过:对象.style.属性来获取(样式在style属性中设置)   offset系列: offsetLeft:距离左边位置的值 offsetTop:距离上面位置的值 offs ...

  6. Ajax获取网页添加到div中

    1:利用DOM获取该 div 的 ID,然后清空该DIV的内容(如果你需要接着里面的内容添加可不要清空):需要注意点是清空最好用“ empty()  ”: 2: 把  async设成true ,否则又 ...

  7. python程序员面试高概率会遇到的技术问题

    本篇只列举会问到的技术问题.其他的问题会在另一篇文章多年职场老狗的面试经验提到. 1. TCP三次握手和四次挥手的过程 2.HTTP协议的状态码 3.讲一下自己用过的设计模式 4.python的多线程 ...

  8. Yii2中多表关联查询

    准备条件: 1.首先准备两张表: customer(用户表)(id, name) order(订单表)(id, customer_id, price) customer 表和 order 表之间是一对 ...

  9. abp大文件附件功能视频教程

    视频分享地址:https://share.weiyun.com/5wtofib

  10. IT兄弟连 HTML5教程 CSS3属性特效 自定义文字

    字体使用是网页设计中不可或缺的一部分.经常地,我们希望在网页中使用某一特定字体,但是该字体并非主流操作系统的内置字体,这样用户在浏览页面的时候就有可能看不到真实的设计.美工设计师最常做的办法是把想要的 ...