selenium+python模拟登陆B站

selenium+python模拟登陆B站

【selenium+python模拟登陆B站】https://www.jianshu.com/u/948da055a416
""" B站模拟登陆即极验. 成功率一般, 具体的轨迹移动可自定义. """ from selenium import webdriver from selenium.webdriver import ActionChains from selenium.webdriver.chrome.options import Options from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By import time import traceback from PIL import Image import re import requests from random import randintdef get_position(driver, klass): """ 获取网页上的验证码图片的偏移位置. :param driver: chrome driver对象. :param klass: 验证码的xpath特征点. :return: 图片的偏移位置列表. """ eles = WebDriverWait(driver, 10).until( EC.presence_of_all_elements_located((By.XPATH, f"//div[@class='{klass}']/div")) ) style_list = [ele.get_attribute('style') for ele in eles]return [re.findall(r'background-position: -(.*?)px -?(.*?)px; ', sty)[0] for sty in style_list]def action_displacement(driver, distance_list): """ 动作链执行, 移动滑块. :param driver: chrome driver对象. :param distance_list: 滑块轨迹移动列表. :return: """ slide_button = WebDriverWait(driver, 10).until( EC.visibility_of_element_located((By.XPATH, "//div[@class='gt_slider_knob gt_show']"))) ActionChains(driver).click_and_hold(slide_button).perform() for i in distance_list: ActionChains(driver).move_by_offset(xoffset=i, yoffset=0).perform() ActionChains(driver).release().perform()returndef acceleration(distance): """ 模拟人为滑块移动, 实为变加速运动, 这里也可以自定义修改为合适的人为移动. :param distance: 图片缺口距离. :return: 滑动轨迹列表. """ t = 0.1 speed = 0 current = 0 a_distance = distance * 4 / 5 distance_list = [] a_list = [1, 2, 3, 5, 4, 6] while current < distance: if current < a_distance: if distance < 50: a = a_list[randint(0, 2)] else: a = a_list[randint(3, 5)] a_move = speed * t + 0.5 * a * t * t speed += (a * t) distance_list.append(round(a_move)) current += a_moveelse: distance_list.extend([3, 3, 2, 2, 1, 1]) breakoffset = sum(distance_list) - distance if offset > 0: distance_list.extend([-1 for i in range(offset)]) elif offset < 0: distance_list.extend([1 for i in range(abs(offset))])distance_list.extend([0, 0, 1, 1, 0, 0, -1, -1])return distance_listdef get_displacement(pixel): """ 获取图片上的缺口距离. :param pixel: 图片的pixel值. :return: 缺口距离. """ offset = set() bg_pix, full_pix = pixelfor x in range(0, 260): for y in range(0, 116): if abs(bg_pix[x, y] - full_pix[x, y]) > 50: offset.add(x)return min(offset)def handle_pic(bg, bg_position): """ 将获得的打乱了的验证图片, 进行重组. :param bg: 图片的名字. :param bg_position: 图片的偏移位置. :return: 图片的pixel值. """ old_im = Image.open(bg) new_im = Image.new('RGB', (312, 116), 125)offset = 0 x = 0 y = 0for posi in bg_position: if offset != 26: new_im.paste(old_im.crop((int(posi[0]) - 1, int(posi[1]), int(posi[0]) + 12, int(posi[1]) + 59)), (x, 0)) offset += 1 x += 10 else: new_im.paste(old_im.crop((int(posi[0]) - 1, int(posi[1]), int(posi[0]) + 12, int(posi[1]) + 59)), (y, 58)) y += 10new_im = new_im.crop((0, 0, 261, 117)) new_im.save(f'new_{bg}')pixel_data = https://www.it610.com/article/new_im.convert("L").load() new_im.load()new_im.close() old_im.close()return pixel_datadef get_picture(driver, klass): """ 获取验证码图片. :param driver: chrome driver对象. :param klass: 验证码图片的xpath特征点. :return: 格式化的验证码图片名. """ ele = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.XPATH, f"//div[@class='{klass}']/div")) ) url = re.findall(r'url\("(.*?)"\); ', ele.get_attribute('style'))[0] with open(f'{klass.split()[0]}.jpg', 'wb') as f: f.write(requests.get(url).content)return f'{klass.split()[0]}.jpg'def chr_opt(): """ chrome browser的设置. :return: 返回设置对象. """ chrome_opt = Options() prefs = { 'profile.default_content_setting_values': { 'notifications': 2 } } chrome_opt.add_experimental_option('prefs', prefs) chrome_opt.add_argument('--headless') chrome_opt.add_argument('--disable-gpu') chrome_opt.add_argument('--window-size=1366,768')return chrome_optdef login_bili(driver): """ 输入登陆的账户和密码. :param driver: 传入webdriver对象即Chrome. :return: """ user_element = driver.find_element_by_xpath("//li[@class='item username status-box']/input") pawd_element = driver.find_element_by_xpath("//li[@class='item password status-box']/input")user_element.clear() user_element.send_keys(user)pawd_element.send_keys(passwd)returnif __name__ == '__main__': ''' 逻辑主. ''' # 配置用户名和密码. url = 'https://passport.bilibili.com/login' user = 'username' passwd = 'password'# 设置bg和full_bg的xpath特征点. bg_klass = 'gt_cut_bg gt_show' full_bg_klass = 'gt_cut_fullbg gt_show'driver = webdriver.Chrome(chrome_options=chr_opt()) try: driver.get(url) # 将 获取的图片(get_picture)和获取的图片偏移位置(get_position)传入到handle_pic处理, 返回重组后的验证图片的pixel data. bg_pixel = handle_pic(get_picture(driver, bg_klass), get_position(driver, bg_klass)) full_pixel = handle_pic(get_picture(driver, full_bg_klass), get_position(driver, full_bg_klass))# 将 获得的验证图片上缺口的距离位置(get_displacement) 传入到acceleration处理, 获得一个滑块轨迹的List. dis_list = acceleration(get_displacement((bg_pixel, full_pixel)) - 5)# 输入账户和密码. login_bili(driver)# 执行action chain. action_displacement(driver, dis_list) time.sleep(5)# 如果登陆成功, 网页会跳转即current_url会发生变化. if driver.current_url[-5:] != 'login': print("登陆成功") else: print("登陆失败") time.sleep(5)except: traceback.print_exc()finally: driver.quit()

    推荐阅读