python 模拟登录B站的示例代码


Posted in Python onDecember 15, 2020

需要将模拟的浏览器,添加到环境变量中哦。代码中用的是chrome

from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
from selenium.common.exceptions import TimeoutException
from PIL import Image
from io import BytesIO
from time import sleep
import random

"""
info:
author:CriseLYJ
github:https://github.com/CriseLYJ/
update_time:2019-3-7
"""


class BiliBili():
  """
  登陆B站, 处理验证码
  电脑的缩放比例需要为100%, 否则验证码图片的获取会出现问题
  """

  def __init__(self, username, password):
    """
    初始化
    """
    options = webdriver.ChromeOptions()
    # 设置为开发者模式,避免被识别
    options.add_experimental_option('excludeSwitches',
                    ['enable-automation'])
    self.browser = webdriver.Chrome(options=options)
    self.url = 'https://passport.bilibili.com/login'
    self.browser.get(self.url)
    self.wait = WebDriverWait(self.browser, 5, 0.2)
    self.username = username
    self.password = password

  def get_button(self):
    """
    获取滑动块, 并且返回
    :return: button
    """
    button = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'gt_slider_knob')))
    return button

  def get_screenshot(self, button):
    """
    获取网页两次截图:
      1. 鼠标悬停于button的截图
      2. 鼠标点击button后的截图
    :param button: 滑动块
    :return: 两次截图的结果
    """
    ActionChains(self.browser).move_to_element(button).perform()
    screenshot1 = self.browser.get_screenshot_as_png()
    screenshot1 = Image.open(BytesIO(screenshot1))
    ActionChains(self.browser).click_and_hold(button).perform()
    screenshot2 = self.browser.get_screenshot_as_png()
    screenshot2 = Image.open(BytesIO(screenshot2))
    return (screenshot1, screenshot2)

  def get_position(self, button):
    """
    获取验证码图片的位置
    :return: 位置的四个点参数
    """
    ActionChains(self.browser).move_to_element(button).perform()
    img = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'gt_box')))
    sleep(2)
    location = img.location
    size = img.size
    print(location, size)
    top, bottom, left, right = location['y'], location['y'] + size['height'], location['x'], \
                  location['x'] + size['width']
    return top, bottom, left, right

  def get_geetest_image(self, button, name1='captcha1.png', name2='captcha2.png'):
    """
    获取两次验证码的截图:
      1. 鼠标悬停于button的截图
      2. 鼠标点击button后的截图
    :param button: 滑动块
    :param name1: 原始验证码保存的名字
    :param name2: 缺块验证码保存的名字
    :return: 两次验证码截图的结果
    """
    top, bottom, left, right = self.get_position(button)
    print('验证码位置', top, bottom, left, right)
    screenshot = self.get_screenshot(button)
    captcha1 = screenshot[0].crop((left, top, right, bottom))
    captcha1.save(name1)
    captcha2 = screenshot[1].crop((left, top, right, bottom))
    captcha2.save(name2)
    return (captcha1, captcha2)

  def login(self):
    """
    打开浏览器,并且输入账号密码
    :return: None
    """
    self.browser.get(self.url)
    username = self.wait.until(EC.element_to_be_clickable((By.ID, 'login-username')))
    password = self.wait.until(EC.element_to_be_clickable((By.ID, 'login-passwd')))
    sleep(1)
    username.send_keys(self.username)
    sleep(1)
    password.send_keys(self.password)

  def is_pixel_equal(self, img1, img2, x, y):
    """
    判断两个像素是否相同
    :param img1: 原始验证码
    :param img2: 缺块验证码
    :param x: 像素点的x坐标
    :param y: 像素点的y坐标
    :return: 像素是否相同
    """
    pixel1 = img1.load()[x-1, y]
    pixel2 = img2.load()[x-1, y]
    threshold = 100
    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, img1, img2):
    """
    获取缺口偏移量
    :param img1: 原始验证码
    :param img2: 缺块验证码
    :return: 第二个缺块的左侧的x坐标
    """
    left = 60 # 大致忽略掉第一个缺块
    for i in range(left, img1.size[0]):
      for j in range(img1.size[1]):
        if not self.is_pixel_equal(img1, img2, i, j):
          left = i
          return left
    return left

  def get_track(self, distance):
    """
    获取滑块移动轨迹的列表
    :param distance: 第二个缺块的左侧的x坐标
    :return: 滑块移动轨迹列表
    """
    track = []
    current = 0
    mid = distance * 2 / 3
    t = 0.2
    v = 0
    distance += 10 # 使滑块划过目标地点, 然后回退
    while current < distance:
      if current < mid:
        a = random.randint(1, 3)
      else:
        a = -random.randint(3, 5)
      v0 = v
      v = v0 + a * t
      move = v0 * t + 0.5 * a * t * t
      current += move
      track.append(round(move))
    for i in range(2):
      track.append(-random.randint(2, 3))
    for i in range(2):
      track.append(-random.randint(1, 4))
    print(track)
    return track

  def move_button(self, button, track):
    """
    将滑块拖动到指定位置
    :param button: 滑动块
    :param track: 滑块运动轨迹列表
    :return: None
    """
    ActionChains(self.browser).click_and_hold(button).perform()
    for i in track:
      ActionChains(self.browser).move_by_offset(xoffset=i, yoffset=0).perform()
      sleep(0.0005)
    sleep(0.5)
    ActionChains(self.browser).release().perform()

  def crack(self):
    """
    串接整个流程:
      1. 输入账号密码
      2. 获取滑动块
      3. 获取两张验证码图片
      4. 获取滑块移动轨迹
      5. 将滑块拖动至指定位置
    :return:
    """
    self.login()
    button = self.get_button()
    captcha = self.get_geetest_image(button)
    left = self.get_gap(captcha[0], captcha[1])
    print(left)
    track = self.get_track(left)
    # 如果尝试登陆失败, 则重新验证, 最多三次
    times = 0
    while times < 3:
      self.move_button(button, track)
      try:
        success = self.wait.until(EC.text_to_be_present_in_element((By.CLASS_NAME, 'gt_info_type'), '验证通过:'))
        print(success)
      except TimeoutException as e:
        times += 1
        print('fail')
      else:
        print('success')
        return None


if __name__ == '__main__':
  ACCOUNT = input('请输入您的账号:')
  PASSWORD = input('请输入您的密码:')

  test = BiliBili(ACCOUNT, PASSWORD) # 输入账号和密码
  test.crack()

以上就是python 模拟登录B站的示例代码的详细内容,更多关于python 模拟登陆B站的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
python根据开头和结尾字符串获取中间字符串的方法
Mar 26 Python
提升Python程序运行效率的6个方法
Mar 31 Python
PyCharm 常用快捷键和设置方法
Dec 20 Python
Python使用Pandas对csv文件进行数据处理的方法
Aug 01 Python
Anaconda 查看、创建、管理和使用python环境的方法
Dec 03 Python
Python的pygame安装教程详解
Feb 10 Python
Python 存取npy格式数据实例
Jul 01 Python
Python列表推导式实现代码实例
Sep 09 Python
用sleep间隔进行python反爬虫的实例讲解
Nov 30 Python
python 写一个文件分发小程序
Dec 05 Python
浅析Django接口版本控制
Jun 26 Python
Python进行区间取值案例讲解
Aug 02 Python
python 模拟登陆163邮箱
Dec 15 #Python
详解numpy1.19.4与python3.9版本冲突解决
Dec 15 #Python
python空元组在all中返回结果详解
Dec 15 #Python
python中delattr删除对象方法的代码分析
Dec 15 #Python
详解python中的三种命令行模块(sys.argv,argparse,click)
Dec 15 #Python
python 基于Apscheduler实现定时任务
Dec 15 #Python
next在python中返回迭代器的实例方法
Dec 15 #Python
You might like
PHP静态类
2006/11/25 PHP
基于PHP生成静态页的实现方法
2013/05/10 PHP
PHP多维数组转一维数组的简单实现方法
2015/12/23 PHP
浅析php静态方法与非静态方法的用法区别
2016/05/17 PHP
实例说明js脚本语言和php脚本语言的区别
2019/04/04 PHP
不错的JS中变量相关的细节分析
2007/08/13 Javascript
javascript 表单验证常见正则
2009/09/28 Javascript
jQuery.autocomplete 支持中文输入(firefox)修正方法
2011/03/10 Javascript
javascript学习笔记(十二) RegExp类型介绍
2012/06/20 Javascript
JavaScript中使用ActiveXObject操作本地文件夹的方法
2014/03/28 Javascript
JavaScript页面模板库handlebars的简单用法
2015/03/02 Javascript
javascript结合Flexbox简单实现滑动拼图游戏
2016/02/18 Javascript
浅谈js基本数据类型和typeof
2016/08/09 Javascript
AngularJS入门教程之迭代器过滤详解
2016/08/18 Javascript
前后端常见的几种鉴权方式(小结)
2019/08/04 Javascript
微信小程序实现多选框全选与反全选及购物车中删除选中的商品功能
2019/12/17 Javascript
Python实现的Google IP 可用性检测脚本
2015/04/23 Python
Python学习入门之区块链详解
2017/07/25 Python
python kmeans聚类简单介绍和实现代码
2018/02/23 Python
对Python中gensim库word2vec的使用详解
2018/05/08 Python
pandas 缺失值与空值处理的实现方法
2019/10/12 Python
关于python中remove的一些坑小结
2021/01/04 Python
html5教程制作简单画板代码分享
2013/12/04 HTML / CSS
韩国家庭购物网上商店:Nsmall
2017/05/07 全球购物
英国网上自行车商店:Tredz Bikes
2019/10/29 全球购物
面向对象概念面试题(.NET)
2016/11/04 面试题
写clone()方法时,通常都有一行代码,是什么?
2012/10/31 面试题
名人演讲稿范文
2013/12/28 职场文书
感恩教师节演讲稿
2014/09/03 职场文书
2014县委书记党的群众路线教育实践活动对照检查材料思想汇报
2014/09/22 职场文书
区长工作作风个人整改措施
2014/10/01 职场文书
党的群众路线教育实践活动领导班子整改措施
2014/10/28 职场文书
认识实习感想
2015/08/10 职场文书
创业计划书之服装
2019/10/07 职场文书
500字作文之关于爸爸
2019/11/14 职场文书
vue中利用mqtt服务端实现即时通讯的步骤记录
2021/07/01 Vue.js