使用python - selenium模拟登陆b站
思路
- 输入用户名密码点击登陆
- 获取验证码的原始图片与有缺口的图片
- 找出两张图片的缺口起始处
- 拖动碎片
功能代码段
# 使用到的库
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站的更多相关文章
- python selenium模拟登陆163邮箱。
selenium是可以模拟浏览器操作. 有些爬虫是异步加载的,通过爬取网页源码是得不到需要的内容.所以可以模拟浏览器去登陆该网站进行爬取操作. 需要安装selenium通过pip install xx ...
- python selenium模拟登陆qq空间
不多说.直接上代码 from selenium import webdriver driver = webdriver.Chrome() driver.get('http://qzone.qq.com ...
- python selenium 模拟登陆百度账号
代码: from selenium import webdriver url = 'https://passport.baidu.com/v2/?login' username = 'your_use ...
- python+selenium 模拟登陆,自动下单
目前写的实在太粗糙,留着,以后来写上
- Python实现模拟登陆
大家经常会用Python进行数据挖掘的说,但是有些网站是需要登陆才能看到内容的,那怎么用Python实现模拟登陆呢?其实网路上关于这方面的描述很多,不过前些日子遇到了一个需要cookie才能登陆的网站 ...
- 【小白学爬虫连载(10)】–如何用Python实现模拟登陆网站
Python如何实现模拟登陆爬取Python实现模拟登陆的方式简单来说有三种:一.采用post请求提交表单的方式实现.二.利用浏览器登陆网站记录登陆成功后的cookies,采用get的请求方式,传入c ...
- python爬虫模拟登陆
python爬虫模拟登陆 学习了:https://www.cnblogs.com/chenxiaohan/p/7654667.html 用的这个 学习了:https://www.cnblogs.co ...
- Selenium模拟登陆百度贴吧
Selenium模拟登陆百度贴吧 from selenium import webdriver from time import sleep from selenium.webdriver.commo ...
- 使用Python+Selenium模拟登录QQ空间
使用Python+Selenium模拟登录QQ空间爬QQ空间之类的页面时大多需要进行登录,研究QQ登录规则的话,得分析大量Javascript的加密解密,这绝对能掉好几斤头发.而现在有了seleniu ...
随机推荐
- UWP 应用启动速度优化——关闭加载动画
准备 在开始之前,我们应该先处理好预启动来加速启动应用.请参见文末链接. 步骤 关闭加载动画主要在包清单文件中进行. 首先,以代码方式打开 Package.appxmanifest,在顶部的 Pack ...
- JS四种判断数据类型的方法:typeof、instanceof、constructor、Object.prototype.toString.call()
1.typeof 1 console.log(typeof ""); //string 2 console.log(typeof 1); //number 3 console.lo ...
- 有一部分程序员还不知道Java 中的注解到底是如何工作的?
作者:人晓 自Java5.0版本引入注解之后,它就成为了Java平台中非常重要的一部分.开发过程中,我们也时常在应用代码中会看到诸如@Override,@Deprecated这样的注解. 这篇文章中, ...
- 5G 调制与解调
调制,就是将原始信号转换为适合在信道中传输的形式的一种过程,在无线通信中,调制一般均指载波调制,而解调则是调制的逆过程,即将原始信号从已调信号中恢复出来. 进行载波调制,主要为实现以下目标: 1)在无 ...
- Linux防火墙的相关资料
1.查看防火墙状态 [root@localhost ~]# service iptables status 2.编辑/etc/sysconfig/iptables文件.我们实例中要打开8080端口和9 ...
- 面试连环炮系列(十五):说说Eureka的高可用方案
说说Eureka的高可用方案 至少3个Eureka实例才能满足高可用,配置方法如下: 准备三个节点node1,node2,node3. 在每个实例的application.xml文件里加入 eurek ...
- SpringCloud服务降级案列
一.什么是服务降级 所有的RPC技术里面服务降级是一个最为重要的话题,所谓的降级指的是当服务的提供方不可使用的时候,程序不会出现异常,而会出现本地的操作 二.服务降级案例 1.目录展示 2.导入依赖 ...
- 【高可用架构】开发机上部署Deploy项目(一)
准备 部署项目的细节可以看这个,传送门Centos 7部署Laravel项目 主机IP:192.168.10.17 [高可用架构]系列链接:待部署的架构介绍 演示 部署Deploy composer ...
- div拖拽效果 JQuery
<!DOCTYPE html> <html> <head> <meta name="description" content=" ...
- 【译】ModSecurity事务生命周期
本篇简要介绍ModSecurity Transaction Lifecycle,也即ModSecurity的事务生命周期. Transaction Lifecycle In ModSecurity, ...