- 首页 > it技术 > >
# =============================================
# --*-- coding: utf-8 --*--
# @Time: 2019-10-21
# @Author: TRHX
# @Blog: www.itrhx.com
# @CSDN: https://blog.csdn.net/qq_36759224
# @FileName: bilibili.py
# @Software: PyCharm
# =============================================
# https://blog.csdn.net/qq_36759224/article/details/102649689 出处
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver import ActionChains
import time
import random
from PIL import Image# 初始化函数
def init():
global url, browser, username, password, wait
url = 'https://passport.bilibili.com/login'
# path是谷歌浏览器驱动的目录,如果已经将目录添加到系统变量,则不用设置此路径
path = r'F:\PycharmProjects\Python3爬虫\chromedriver.exe'
chrome_options = Options()
chrome_options.add_argument('--start-maximized')
# browser = webdriver.Chrome(executable_path=path, chrome_options=chrome_options)
browser = webdriver.Chrome(chrome_options=chrome_options)
# 你的哔哩哔哩用户名
username = '186*****'
# 你的哔哩哔哩登录密码
password = 'zz***'
wait = WebDriverWait(browser, 20)# 登录函数
def login():
browser.get(url)
# 获取用户名输入框
user = wait.until(EC.presence_of_element_located((By.ID, 'login-username')))
# 获取密码输入框
passwd = wait.until(EC.presence_of_element_located((By.ID, 'login-passwd')))
# 输入用户名
user.send_keys(username)
# 输入密码
passwd.send_keys(password)
# 获取登录按钮
login_btn = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'a.btn.btn-login')))
# 随机暂停几秒
time.sleep(random.random() * 3)
# 点击登陆按钮
login_btn.click()# 验证码元素查找函数
def find_element():
# 获取带有缺口的图片
c_background = wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, 'canvas.geetest_canvas_bg.geetest_absolute')))
# 获取需要滑动的图片
c_slice = wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, 'canvas.geetest_canvas_slice.geetest_absolute')))
# 获取完整的图片
c_full_bg = wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, 'canvas.geetest_canvas_fullbg.geetest_fade.geetest_absolute')))
# 隐藏需要滑动的图片
hide_element(c_slice)
# 保存带有缺口的图片
save_screenshot(c_background, 'back')
# 显示需要滑动的图片
show_element(c_slice)
# 保存需要滑动的图片
save_screenshot(c_slice, 'slice')
# 显示完整的图片
show_element(c_full_bg)
# 保存完整的图片
save_screenshot(c_full_bg, 'full')# 设置元素不可见
def hide_element(element):
browser.execute_script("arguments[0].style=arguments[1]", element, "display: none;
")# 设置元素可见
def show_element(element):
browser.execute_script("arguments[0].style=arguments[1]", element, "display: block;
")# 验证码截图函数
def save_screenshot(obj, name):
try:
# 首先对出现验证码后的整个页面进行截图保存
pic_url = browser.save_screenshot('.\\bilibili.png')
print("%s:截图成功!" % pic_url)
# 计算传入的obj,也就是三张图片的位置信息
left = obj.location['x']
top = obj.location['y']
right = left + obj.size['width']
bottom = top + obj.size['height']
# 打印输出一下每一张图的位置信息
print('图:' + name)
print('Left %s' % left)
print('Top %s' % top)
print('Right %s' % right)
print('Bottom %s' % bottom)
print('')
# 在整个页面截图的基础上,根据位置信息,分别剪裁出三张验证码图片并保存
im = Image.open('.\\bilibili.png')
im = im.crop((left, top, right, bottom))
file_name = 'bili_' + name + '.png'
im.save(file_name)
except BaseException as msg:
print("%s:截图失败!" % msg)# 滑动模块的主函数
def slide():
distance = get_distance(Image.open('.\\bili_back.png'), Image.open('.\\bili_full.png'))
print('计算偏移量为:%s Px' % distance)
trace = get_trace(distance - 5)
move_to_gap(trace)
time.sleep(3)# 计算滑块移动距离函数
def get_distance(bg_image, fullbg_image):
# 滑块的初始位置
distance = 60
# 遍历两张图片的每个像素
for i in range(distance, fullbg_image.size[0]):
for j in range(fullbg_image.size[1]):
# 调用缺口位置寻找函数
if not is_pixel_equal(fullbg_image, bg_image, i, j):
return i# 缺口位置寻找函数
def is_pixel_equal(bg_image, fullbg_image, x, y):
# 获取两张图片对应像素点的RGB数据
bg_pixel = bg_image.load()[x, y]
fullbg_pixel = fullbg_image.load()[x, y]
# 设定一个阈值
threshold = 60
# 比较两张图 RGB 的绝对值是否均小于定义的阈值
if (abs(bg_pixel[0] - fullbg_pixel[0] < threshold) and abs(bg_pixel[1] - fullbg_pixel[1] < threshold) and abs(
bg_pixel[2] - fullbg_pixel[2] < threshold)):
return True
else:
return False# 构造移动轨迹函数
def get_trace(distance):
trace = []
# 设置加速距离为总距离的4/5
faster_distance = distance * (4 / 5)
# 设置初始位置、初始速度、时间间隔
start, v0, t = 0, 0, 0.1
while start < distance:
if start < faster_distance:
a = 10
else:
a = -10
# 位移
move = v0 * t + 1 / 2 * a * t * t
# 当前时刻的速度
v = v0 + a * t
v0 = v
start += move
trace.append(round(move))
# trace 记录了每个时间间隔移动了多少位移
return trace# 模拟拖动函数
def move_to_gap(trace):
# 获取滑动按钮
slider = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'div.geetest_slider_button')))
# 点击并拖动滑块
ActionChains(browser).click_and_hold(slider).perform()
# 遍历运动轨迹获取每小段位移距离
for x in trace:
# 移动此位移
ActionChains(browser).move_by_offset(xoffset=x, yoffset=0).perform()
time.sleep(0.5)
# 释放鼠标
ActionChains(browser).release().perform()if __name__ == '__main__':
init()
login()
find_element()
slide()
推荐阅读