第二十九节: 模拟登陆

一、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=""')  # 获取完整的验证码
原文地址:https://www.cnblogs.com/zhaco/p/11332443.html