思路

  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. VMware虚拟机安装Linux(CentOS)系统

    vmware workstation 虚拟机官方下载路径:https://www.vmware.com/cn/products/workstation-pro/workstation-pro-eval ...

  2. MySQL使用可重复读作为默认隔离级别的原因

    一般的DBMS系统,默认都会使用读提交(Read-Comitted,RC)作为默认隔离级别,如Oracle.SQL Server等,而MySQL却使用可重复读(Read-Repeatable,RR). ...

  3. 关于Java调用接入微信、支付宝支付提现

    前言: 本篇文章介绍关于自己写的一个集成微信.支付宝的支付.提现等功能的介绍,本项目已在码云上进行开源,欢迎大家一起来进行改造,使进行更好的创新供大家使用:也有对应的pom文件坐标可以导入,因目前不知 ...

  4. ThinkPhp RBAC实现原理

    RBAC是英文Role-Based Access Control的缩写,是基于角色访问进行控制的机制.意思是给每个用户设定一个角色,然后根据这个角色来判断用户的权限. 在此基于ThinkPhp的MVC ...

  5. VS2019 开发Django(七)------VS2019不能格式化html代码

    如题,在VS2019中不能使用快捷键Ctrl+K,+D格式化html代码,印象中之前的版本是可以的吧!不太确定,这给我带来了很大的麻烦,在编写Django项目的时候,标准的模板是新建的html文件,不 ...

  6. Java 密码加盐

    只对密码进行md5加密很容易反推出来,另外两个用户的密码相同时,数据库保存相同的密码,知道一个用户的密码就知道另一个.解决方法是在用户的短密码后面加上一段长字符,再计算 md5,这样反推出原始密码就变 ...

  7. Navicat Premium从远程Mysql数据库复制到本地数据库的方法

    之前做在本地测试总是先去现在下一份数据库的sql,然后再在本地建一个相同的,导入sql.然后觉得有点麻烦,现在发现了一个直接远程直接复制一份到本地的方法 工具:Navicat Premium 1.先连 ...

  8. CentOS 7上的主机名设置和基本网络管理

    主机名 CentOS 6 查看. # hostname 设置. # hostname NEW_NAME 设置完成后,xshell的会话中不会显示NEW_NAME,可通过重新登录会话来显示.不过实际上我 ...

  9. 如何使用TG Pro for Mac的自定义控制功能完全覆盖系统

    在某些情况下,可能需要完全覆盖系统风扇控制并使用自定义算法.通过将Auto Boost规则的强大功能与覆盖系统功能相结合,可以使用TG Pro.请记住,当风扇模式设置为Auto Boost时,这将完全 ...

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

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