使用python - selenium模拟登陆b站

思路

  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()

原文地址:https://www.cnblogs.com/NFii/p/11707159.html

时间: 2024-11-10 11:09:27

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

python selenium 模拟登陆百度账号

代码: from selenium import webdriver url = 'https://passport.baidu.com/v2/?login' username = 'your_username' passwd = "your_password" driver = webdriver.Chrome() # 打开chrome浏览器 driver.get(url) # 打开指定的网页 input_username = driver.find_element_by_id(&q

selenium 模拟登陆豆瓣,爬去武林外传的短评

selenium 模拟登陆豆瓣,爬去武林外传的短评: 在最开始写爬虫的时候,抓取豆瓣评论,我们从F12里面是可以直接发现接口的,但是最近豆瓣更新,数据是JS异步加载的,所以没有找到合适的方法爬去,于是采用了selenium来模拟浏览器爬取. 豆瓣登陆也是改了样式,我们可以发现登陆页面是在另一个frame里面 所以代码如下: # -*- coding:utf-8 -*- # 导包 import time from selenium import webdriver from selenium.we

python爬虫 模拟登陆校园网-初级

最近跟同学学习爬虫的时候看到网上有个帖子,好像是山大校园网不稳定,用py做了个模拟登陆很有趣,于是我走上了一条不归路..... 先上一张校园网截图 首先弄清一下模拟登陆的原理: 1:服务器判定浏览器登录使用浏览器标识,需要模拟登陆 2: 需要post账号,密码,以及学校id python走起,我用的2.7版本,用notepad++写的,绑定python可以直接运行 由于是模拟网页登陆,需要导入urllib urllib2 cookielib库,前两个有与网页直接的接口,cookielib就是用来

九、Python+Selenium模拟用QQ登陆腾讯课堂,并提取报名课程(练习)

研究QQ登录规则的话,得分析大量Javascript的加密解密,比较耗时间.自己也是练习很少,短时间成功不了.所以走了个捷径. Selenium是一个WEB自动化测试工具,它运行时会直接实例化出一个浏览器,完全模拟用户的操作,比如点击链接.输入表单,点击按钮提交等.所以我们使用它可以很方便的来登录. 但是作为新手还是多多分析,尽量少用这个,以便提高自己的技术.在研究几天,在写一个自己满意的. import time # import random from bs4 import Beautifu

九、Python+Selenium模拟登录

研究QQ登录规则的话,得分析大量Javascript的加密解密,比较耗时间.自己也是练习很少,短时间成功不了.所以走了个捷径. Selenium是一个WEB自动化测试工具,它运行时会直接实例化出一个浏览器,完全模拟用户的操作,比如点击链接.输入表单,点击按钮提交等.所以我们使用它可以很方便的来登录. 但是作为新手还是多多分析,尽量少用这个,以便提高自己的技术.在研究几天,在写一个自己满意的. import time # import random from bs4 import Beautifu

python + selenium 模拟键盘升级版PyUserInput

前言在web自动化下载操作时,有时候会弹出下载框,这种下载框不属于web的页面,是没办法去定位的(有些同学一说到点击,脑袋里面就是定位!定位!定位!)有时候我们并不是非要去定位到这个按钮再去点击,学会使用键盘的快捷键操作,也能达到一样的效果.之前讲过一篇Selenium2+python自动化75-非input文件上传(SendKeys)这个当时是基于python2写的.最近很多小伙伴开始用python3了,这个SendKeys在python3上没法用,python3需要用PyUserInput,

selenium模拟登陆

案例一:网站模拟登录 # -*- coding:utf-8 -*- # douban.py #coding=utf-8 import time from selenium import webdriver from selenium.webdriver.common.keys import Keys class Douban(): def __init__(self): self.url = "https://www.douban.com/" self.driver = webdriv

python selenium 模拟手机浏览器

脚本如下: from selenium import webdriver mobile = {'deviceName': 'Apple iPhone 4'} //设置所模拟的硬件 path='C:\\Program Files (x86)\\Google\\Chrome\\Application\\chromedriver.exe' options = webdriver.ChromeOptions() options.add_experimental_option('mobileEmulati

java+selenium模拟登陆新浪微博demo

java代码 import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.firefox.FirefoxDriver; public class crawler { public static