2020.3.18selenium破解滑动验证码模拟登录b站(附逻辑导图)

Linnea ·
更新时间:2024-11-10
· 892 次阅读

学习了别人破解滑动验证码的过程,自己做了个逻辑图分享给大家,代码也在下面
逻辑导图
在这里插入图片描述
代码

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 base64 class LoginBiliBili: def __init__(self, username, password): """ 初始化数据 :param username: bilibili账号 :param password: 密码 """ options = webdriver.ChromeOptions() # 设置为开发者模式,避免被识别 options.add_experimental_option('excludeSwitches', ['enable-automation']) self.username = username self.password = password # 定义浏览器 self.browser = webdriver.Chrome(options=options) # 定义显示等待 self.wait = WebDriverWait(self.browser, 50) # bilibili登录url self.url = 'https://passport.bilibili.com/login' def open(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) login_button = self.wait.until( EC.presence_of_element_located((By.XPATH, '//*[@id="geetest-wrap"]/div/div[5]/a[1]'))) # 点击登录 login_button.click() # 休眠, 让验证码图片加载出来 sleep(2) def get_geetest_image(self): """ 获取极验验证码图片 :return: c_image(王者验证图) ic_image(有缺失的验证图) """ """ 完整的验证图 页面源码: """ # 执行js 拿到canvas画布里面的图片数据 js = 'return document.getElementsByClassName("geetest_canvas_fullbg")[0].toDataURL("image/png");' # 图片数据 complete_img_data = self.browser.execute_script(js) # base64 编码的图片信息 complete_img_base64 = complete_img_data.split(',')[1] # 转成bytes类型 complete_img = base64.b64decode(complete_img_base64) # 加载图片 return 回去对比 c_image = Image.open(BytesIO(complete_img)) # c_image.show() # 保存图片 (可不必保存) c_image.save('./bilibili_captcha/c_image.png') """ 有缺失的验证码图 页面源码: """ # 执行js 拿到canvas画布里的图片数据 js = 'return document.getElementsByClassName("geetest_canvas_bg")[0].toDataURL("image/png");' # 图片数据 incomplete_img_data = self.browser.execute_script(js) # base64 编码的图片信息 incomplete_img_base64 = incomplete_img_data.split(',')[1] # 转为bytes类型 incomplete_img = base64.b64decode(incomplete_img_base64) # 直接加载图片 return 回去对比 ic_image = Image.open(BytesIO(incomplete_img)) # ic_image.show() # 保存图片(可不必保存) ic_image.save('./bilibili_captcha/ic_image.png') return c_image, ic_image def is_pixel_similar(self, c_image, ic_image, x, y): """ 比较两张图片的像素点 注意: 像素点比较是有偏差的, 需要允许一定范围的误差, 我们可以设置一个阈值 :param ic_image: :param c_image: :param x: :param y: :return: 当像素点不相同时, 返回 False """ # 获取两张图片执行位置的像素点 c_pixel = c_image.load()[x, y] ic_pixel = ic_image.load()[x, y] # 阈值 允许误差 threshold = 10 # 对比 if abs(c_pixel[0] - ic_pixel[0]) < threshold and \ abs(c_pixel[1] - ic_pixel[1]) < threshold and \ abs(c_pixel[2] - ic_pixel[2]) < threshold: return True return False def get_slice_gap(self, c_image, ic_image): """ 获取缺口的偏移量 通过比较两张图片的所有像素点, 获取两张图片是从哪里开始不同 从而得到 移动块 要在 x 方向移动的距离 :param c_image: 完整的图片 :param ic_image: 有缺失的图片 :return: 缺口的偏移量 """ # ic_image.size:['width', 'height'] for x in range(c_image.size[0]): for y in range(c_image.size[1]): if not self.is_pixel_similar(c_image, ic_image, x, y): # 移动块只在水平方向移动 只需返回 x return x def drag_slider(self, gap): """ 拖动滑块 :param gap: 需要拖动的距离 :return: None """ slider = self.wait.until(EC.presence_of_element_located((By.XPATH, '/html/body/div[2]/div[2]/div[6]/div/div[1]/div[2]/div[2]'))) # 抓住滑块 ActionChains(self.browser).click_and_hold(on_element=slider).perform() # 移动 只在水平方向上移动 ActionChains(self.browser).move_by_offset(xoffset=gap // 2, yoffset=0).perform() sleep(1) ActionChains(self.browser).move_by_offset(xoffset=gap // 2, yoffset=0).perform() # 释放滑块 ActionChains(self.browser).release().perform() """ 判断是否登陆成功 :return: 成功返回 True 失败返回False """ def login_success(self): """ 判断是否登陆成功 :return: 成功返回 True 失败返回False """ try: # 登录成功后 界面上会有一个消息按钮 return bool( self.wait.until(EC.text_to_be_present_in_element((By.CLASS_NAME, 'mini-upload'), '投稿')) ) except TimeoutException: return False def login(self): """ 开始 :return: None """ # 打开浏览器, 输入账号 密码, 点击登陆 self.open() # 获取验证图 ic_image(有缺失的验证图) c_image(完整的验证图) c_image, ic_image = self.get_geetest_image() # 获取缺口的偏移量 gap = self.get_slice_gap(c_image, ic_image) print(f'缺口的偏移量为:{gap}') # 拖动滑块 self.drag_slider(gap - 6) sleep(8) if self.login_success(): print('登陆成功') else: self.login() if __name__ == '__main__': login = LoginBiliBili('***', '***') # 输入账号和密码 login.login()
作者:L.1awliet



滑动验证码 滑动验证 验证码 selenium

需要 登录 后方可回复, 如果你还没有账号请 注册新账号
相关文章