使用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 ...
随机推荐
- salt
更新于 3.25 23:16 salt简介 SaltStack是一个服务器基础架构集中化管理平台,具备配置管理.远程执行.监控等功能,基于Python语言实现,结合轻量级消息队列(ZeroMQ)与Py ...
- 你不知道的JavaScript(中)读书笔记(二)
第三章 原生函数 常用的原生函数(内建函数)有: String() Number() Boolean Array() Object() Function() RegExp() Date() Erroe ...
- Django聚合查询 orm字段及属性
目录 一 聚合查询 1. 级联 级联删除 级联更新 2. 聚合函数 使用 aggregate 使用场景 3. 分组查询 语法 使用 annotate 代码 4. F与Q查询 F查询 Q查询 二 ORM ...
- python 多线程编程之threading模块(Thread类)创建线程的三种方法
摘录 python核心编程 上节介绍的thread模块,是不支持守护线程的.当主线程退出的时候,所有的子线程都将终止,不管他们是否仍在工作. 本节开始,我们开始介绍python的另外多线程模块thre ...
- leaflet视频监控播放(附源码下载)
前言 leaflet 入门开发系列环境知识点了解: leaflet api文档介绍,详细介绍 leaflet 每个类的函数以及属性等等 leaflet 在线例子 leaflet 插件,leaflet ...
- PromiseKit基本使用及源码解析
Promise处理一系列异步操作的应用框架,能够保证顺序执行一系列异步操作,当出错时可以通过catch捕获错误进行处理.Promise框架也是很好的诠释了swift的面相协议编程以及函数式编程 两种类 ...
- oopday02(面向对象-构造方法&静态static)
面向对象之封装 01_面向对象(构造方法Constructor概述和格式) * A:构造方法概述和作用 * 给对象的数据(属性)进行初始化 * B:构造方法格式特点 * a:方法名与类名相同(大小也要 ...
- Bash脚本编程之算术运算
简介 Bash所支持的算术运算和C语言是一样的,这里指的是操作符(operator)以及它们的优先级(precedence).结合性(associativity)和值,详见Shell Arithmet ...
- 微信 电脑版 HOOK(WeChat PC Hook)- 远程线程注入dll原理
Windows加载dll的特性 1.Windows系统中,每个exe软件运行的时候,会加载系统模块kernel32.dll 2.所有加载进exe软件的系统模块kernel32.dll,内存地址都是一样 ...
- 基于XML的开发
基于XML的开发 1.定义一个切面类 /** * Created by zejian on 2017/2/20.*/ public class MyAspectXML { public void be ...