• 第二十九节: 模拟登陆


    一、126,163邮箱模拟登陆

     1 # -*- coding:utf-8 -*-
     2 import time
     3 from selenium import webdriver
     4 def login126_or_163emall(url):
     5     login_name = input("请输入账号:")
     6     login_password = input("请输入密码:")
     7 
     8     # 打开自动测试软件Chrome
     9     driver = webdriver.Chrome(executable_path="D:chromedriver.exe")
    10 
    11     # 模拟窗口最大化
    12     driver.maximize_window()
    13 
    14     # 打开目标网站
    15     driver.get(url=url)
    16     time.sleep(10)
    17 
    18     # 切换为密码登录
    19     password_login_button = driver.find_element_by_id("lbNormal")
    20     password_login_button.click()
    21 
    22     # 由于126邮箱是iframe嵌套,所以要切换到iframe窗口
    23     elem = driver.find_element_by_css_selector("iframe[id^='x-URS-iframe']")
    24 
    25     # 用frame的index来定位,定位iframe窗口
    26     driver.switch_to.frame(elem)
    27 
    28     # 定位到账号输入框,不需要输入@126.com
    29     user_name = driver.find_element_by_name("email")
    30     user_name.send_keys(login_name)
    31 
    32     # 定位到密码输入框
    33     user_password = driver.find_element_by_name("password")
    34     user_password.send_keys(login_password)
    35     time.sleep(3)
    36 
    37     # 定位到登录按钮
    38     login_button = driver.find_element_by_id("dologin")
    39     login_button.click()
    40     time.sleep(5)
    41 
    42     # 获取用户登录的cookies,返回一个字典
    43     cookies = driver.get_cookies()[0]
    44     print(cookies)
    45     time.sleep(10)
    46 
    47     # 关闭模拟浏览器窗口
    48     driver.close()
    49 
    50 if __name__ == '__main__':
    51     # url = "https://mail.126.com/"     # 126邮箱url
    52     url = "https://mail.163.com/"       # 163邮箱url
    53     login126_or_163emall(url=url)
    126,163邮箱模拟登陆

    输出的cookies如下:

    """
    {'domain': '.163.com', 'expiry': 4717308714, 'httpOnly': False, 'name': '_ntes_nnid',
     'path': '/', 'secure': False, 'value': 'cf36cf83b0562fccb3ab872f3b1dfa4c,1563708714807'}
     """

    二、哔哩哔哩模拟登陆

      1 import time
      2 import random
      3 from PIL import Image
      4 from io import BytesIO
      5 from selenium import webdriver
      6 from selenium.webdriver.common.by import By
      7 from selenium.webdriver import ActionChains
      8 from selenium.webdriver.support.wait import WebDriverWait
      9 from selenium.webdriver.support import expected_conditions as EC
     10 
     11 border = 6          # 滑块左边框到验证图片左边框的距离
     12 
     13 class CrackGeetest():
     14     def __init__(self):
     15         self.url = 'https://passport.bilibili.com/login'
     16         self.browser = webdriver.Chrome(r"D:chromedriver.exe")
     17 
     18         # 设置浏览器为最大窗口
     19         self.browser.maximize_window()
     20         self.wait = WebDriverWait(self.browser,timeout=5)
     21 
     22     def close(self):
     23         self.browser.close()        # 关闭浏览器
     24         self.browser.quit()         # 退出并停止执行chromedriver.exe
     25 
     26 
     27     # 获取带缺口的图片
     28     def get_geetest_image(self, name='captcha.png'):
     29 
     30         # 获取完整的验证图片
     31         img = self.wait.until(EC.presence_of_element_located((By.XPATH, '/html/body/div[2]/div[2]/div[6]/div/div[1]/div[1]/div/a/div[1]')))
     32         time.sleep(2)
     33         location = img.location                             # 获取元素位置
     34         size = img.size                                     # 获取元素尺寸
     35         print(location,size)
     36 
     37         top = location['y']
     38         bottom = location['y'] + size['height']
     39         left = location['x']
     40         right = location['x'] + size['width']
     41         print('验证码位置', top, bottom, left, right)
     42 
     43         # 获取当前窗口的屏幕截图(二进制数据)
     44         screenshot = self.browser.get_screenshot_as_png()
     45 
     46         # 使用BytesIO对象在内存中读写bytes(就是读取截图)
     47         screenshot = Image.open(BytesIO(screenshot))
     48         screenshot.save(r"D:photoimagescreenshot.png" )
     49 
     50         # 按照图片验证码的大小尺寸进行剪切
     51         captcha = screenshot.crop((left, top, right, bottom))
     52 
     53         # 将图片验证码保存到指定路径
     54         captcha.save(r"D:photoimage\%s"%name)
     55         return captcha
     56 
     57 
     58         # 获取缺口位置
     59     def get_gap(self, img1, img2):
     60         left = 60                                               # 滑块的宽度+滑块左边框到验证图片左边框的距离
     61         for i in range(left, img1.size[0]):                     # 遍历不带缺口的图片img1的RGB像素点
     62             for j in range(img1.size[1]):
     63                 if not self.is_pixel_equal(img1, img2, i, j):   # 判断两张图片同一位置的像素点是否相等
     64                     left = i
     65                     return left
     66         return left
     67 
     68 
     69     # 判断两张验证图片同一位置的像素点是否相同
     70     def is_pixel_equal(self, img1, img2, x, y):
     71 
     72         # 取两个图片的像素点
     73         pix1 = img1.load()[x,y]
     74         pix2 = img2.load()[x,y]
     75         threshold = 60                      # 阈值
     76         pix_r = abs(pix1[0] - pix2[0])      # R
     77         pix_g = abs(pix1[1] - pix2[1])      # G
     78         pix_b = abs(pix1[2] - pix2[2])      # B
     79         if (pix_r < threshold) and (pix_g < threshold) and (pix_b < threshold):
     80             return True
     81         else:
     82             return False
     83 
     84     # 获取移动轨迹
     85     def get_track(self, distance):
     86         track = []                          # 移动轨迹
     87         current = 0                         # 当前位移
     88         mid = distance * 3 / 4              # 减速阈值
     89         t = random.randint(2,3)/10          # 计算间隔
     90         v = 0                               # 初速度
     91         distance += 5
     92         while current < distance:           # 判断当前位移是否小于缺口距离
     93             if current < mid:               # 如果当前位移小于减速的阈值
     94                 a = 2                       # 则加速度为正
     95             else:
     96                 a = -3                      # 否则加速度为负
     97             v0 = v                          # 初速度v0
     98             v = v0 + a * t                  # 当前速度v (v = v0 + at)
     99             x = v0*t + 1/2*a*t*t            # 移动距离x (x = v0t + 0.5at^2)
    100             current += x                    # 当前位移
    101             track.append(round(x))          # 加入轨迹(round为四舍五入)
    102         return track
    103 
    104 
    105     # 移动缺口滑块
    106     def move_to_gap(self, slider, tracks):
    107         """
    108         :param slider: 滑块
    109         :param tracks: 移动轨迹
    110         """
    111         random.shuffle(tracks)
    112 
    113         # 创建一个鼠标移动的动作链,在滑块上按住的鼠标左键,并执行。
    114         ActionChains(self.browser).click_and_hold(slider).perform()
    115 
    116         # 正向移动轨迹
    117         for x in tracks:
    118             # 创建一个鼠标移动的动作链,将鼠标移动到当前鼠标位置的偏移位置(x,0)上,并执行。
    119             ActionChains(self.browser).move_by_offset(xoffset=x, yoffset=0).perform()
    120 
    121         # 模拟人工滑动超过缺口位置返回至缺口的情况,同时还加入了随机数,都是为了更贴近人工滑动轨迹
    122         action = ActionChains(self.browser).move_by_offset(xoffset=-1, yoffset=0)
    123         time.sleep(0.015)
    124         action.perform()
    125         time.sleep(random.randint(6, 10) / 10)
    126         action.perform()
    127         time.sleep(0.04)
    128         action.perform()
    129         time.sleep(random.randint(6, 10) / 10)
    130         action.perform()
    131         time.sleep(0.019)
    132         action.perform()
    133         time.sleep(random.randint(6, 10) / 10)
    134         ActionChains(self.browser).move_by_offset(xoffset=1, yoffset=0).perform()
    135 
    136         # 模拟抖动(由于释放鼠标是会产生抖动)
    137         ActionChains(self.browser).move_by_offset(xoffset=-3, yoffset=0).perform()
    138         ActionChains(self.browser).move_by_offset(xoffset=2, yoffset=0).perform()
    139 
    140         time.sleep(0.5)
    141         # 创建一个鼠标行为的动作链,释放滑块上的鼠标按钮,并执行。
    142         ActionChains(self.browser).release().perform()
    143 
    144     def crack(self):
    145         try:
    146             # 打开网页
    147             self.browser.get(self.url)
    148             # 获取用户名输入框
    149             emall = self.wait.until(EC.presence_of_all_elements_located((By.XPATH,'//*[@id="login-username"]')))[0]
    150 
    151             # 获取密码输入框
    152             password = self.wait.until(EC.presence_of_all_elements_located((By.XPATH,'//*[@id="login-passwd"]')))[0]
    153 
    154             # 发送用户名
    155             emall.send_keys("15612345678")
    156 
    157             # 发送密码
    158             password.send_keys("1234567890")
    159 
    160             # 点击登录按钮使之显示验证图片
    161             loginbutton = self.wait.until(EC.element_to_be_clickable((By.XPATH, '//*[@id="geetest-wrap"]/ul/li[5]/a[1]')))
    162             loginbutton.click()
    163 
    164             # 确认验证图片加载完成(获取完整的验证码div)
    165             self.wait.until(EC.presence_of_element_located((By.XPATH, '/html/body/div[2]/div[2]/div[6]/div')))
    166 
    167             # 获取移动滑块(slider:滑块)
    168             slider = self.wait.until(EC.element_to_be_clickable((By.XPATH, '/html/body/div[2]/div[2]/div[6]/div/div[1]/div[2]/div[2]')))
    169 
    170             # 获取带缺口的验证码图片(完整的验证图片)
    171             image1 = self.get_geetest_image('captcha1.png')
    172 
    173             #========= 在当前窗口执行JavaScript语句(由于验证码原图被切分成搞多块)=========#
    174             # 组合验证码方法一:
    175             element = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'canvas.geetest_canvas_fullbg.geetest_fade.geetest_absolute')))
    176             self.browser.execute_script("arguments[0].style=arguments[1]",element,"display: block;")
    177 
    178             # 组合验证码方法二:(本人建议使用此方法)
    179             # self.browser.execute_script('document.querySelectorAll("canvas")[2].style=""')  # 获取缺块儿验证码
    180             # self.browser.execute_script('document.querySelectorAll("canvas")[3].style=""')  # 获取完整的验证码
    181 
    182             # 获取带缺口的验证码图片(不完整的验证图片)
    183             image2 = self.get_geetest_image('captcha2.png')
    184 
    185             # 调用获取缺口位置函数(滑块的位置)
    186             gap = self.get_gap(image1, image2)
    187 
    188             # 减点滑块左边框到验证图片左边框的距离
    189             gap -= border
    190             print('滑块的位置', gap)
    191 
    192             # 调用获取移动轨迹函数(track:移动轨迹)
    193             track = self.get_track(gap)
    194 
    195             # 调用移动缺口滑块函数进行滑动
    196             self.move_to_gap(slider, track)
    197             time.sleep(1)
    198             # 获取验证完成后返回的数据“验证成功”
    199             success = self.wait.until(EC.text_to_be_present_in_element((By.XPATH, '/html/body/div[2]/div[2]/div[3]/div[2]'), '验证成功'))
    200             print(success)
    201             time.sleep(5)
    202 
    203             # 关闭浏览器
    204             self.close()
    205         except:
    206             print('Failed-Retry')       # 失败重试
    207             self.crack()
    208 
    209 if __name__ == '__main__':
    210     crack = CrackGeetest()
    211     crack.crack()
    哔哩哔哩模拟登陆

    由于哔哩哔哩验证码是极验的滑动验证码,验证码图片是由很多个小块图片碎片组合而成,所以解决办法如下:

    #========= 在当前窗口执行JavaScript语句(由于验证码原图被切分成搞多块)=========#
                # 组合验证码方法一:
                element = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'canvas.geetest_canvas_fullbg.geetest_fade.geetest_absolute')))
                self.browser.execute_script("arguments[0].style=arguments[1]",element,"display: block;")
    
                # 组合验证码方法二:(本人建议使用此方法)
                # self.browser.execute_script('document.querySelectorAll("canvas")[2].style=""')  # 获取缺块儿验证码
                # self.browser.execute_script('document.querySelectorAll("canvas")[3].style=""')  # 获取完整的验证码
  • 相关阅读:
    log4j日志基本配置
    MyBatis基本应用
    Java properties配置文件
    Java DAO模式
    Java方式 MySQL数据库连接
    bug 复制代码没有审查,没有完全就该变量名
    cocos3 深入理解tiledmap
    cocos3 深入理解单例模式
    cocos3 CC_BREAK_IF(m_pGameMap==NULL);
    cocos2d3 宏定义屏幕宽高,这样就不用重复获取了
  • 原文地址:https://www.cnblogs.com/zhaco/p/11332443.html
Copyright © 2020-2023  润新知