滑动验证码(无原图片处理)

 

  1 from _pytest.mark import param
  2 from seleniumbase.config import settings
  3 from urllib3 import request
  4 from pageobject.basepage import BasePage
  5 import allure
  6 from PIL import Image
  7 from io import BytesIO
  8 import re
  9 import random
 10 import base64
 11 from tools import common
 12 from selenium.webdriver import ActionChains
 13 import cv2
 14 from pageobject.page.navigation_bar import Navigation
 15 import requests
 16 import settings
 17 import json
 18 import time
 19 
 20 
 21 class Login(BasePage):
 22     url = '/login'
 23     usernameInput = "//input[@name='username']"
 24     passwordInput = "//input[@name='password']"
 25     loginButton = "//input[@value='登录']/.."
 26     slider = "//div[@id='slider']"
 27     smallImageblocks = "//img[@class='smallImageblocks']"
 28     bgImage = "//img[@class='bgImage']"
 29 
 30     def open(self):
 31         '''
 32         打开账号密码登录页
 33         '''
 34         self._open(self.url)
 35 
 36     def type_name(self, value):
 37         '''
 38         输入用户名
 39         '''
 40         self.input(self.usernameInput, value)
 41 
 42     def type_pw(self, value):
 43         '''
 44         输入密码
 45         '''
 46         self.input(self.passwordInput, value)
 47 
 48     def click_login(self):
 49         '''
 50         点击登录
 51         '''
 52         self.click(self.loginButton)
 53 
 54     def hover_slider(self):
 55         '''
 56         停留在滑块上,并设置图片可见
 57         '''
 58         self.hover_on_element(self.slider)
 59         self.set_attribute(self.bgImage+"/..", 'class', 'slidePanel')
 60 
 61     def set_slider_success(self):
 62         '''
 63         设置图片验证成功
 64         '''
 65         self.set_attribute(self.slider+"/../..", 'class',
 66                            "sliderContainer sliderContainer_success")
 67 
 68 
 69 class VerificationCode(Login):
 70     def get_img(self, loc):
 71         '''
 72         获取图片
 73         :param driver:
 74         :param div_class:
 75         :param num:
 76         :return:
 77         '''
 78         imge_url = ''
 79         location = {}
 80         imge_url = self.get_attribute(loc, 'src')
 81         try:
 82             location['x'] = re.findall(
 83                 r'padding-top: (.*?)px;', self.get_attribute(loc, 'style'))[0]
 84         except Exception:
 85             location['x'] = 0
 86         try:
 87             location['y'] = re.findall(
 88                 r'padding-top: (.*?)px; left: (.*?)px;', self.get_attribute(loc, 'style'))[1]
 89         except Exception:
 90             location['y'] = 0
 91         b64_data = imge_url.split(';base64,')[1]
 92         data = base64.b64decode(b64_data)
 93         img_content = BytesIO(data)
 94         image = Image.open(img_content)
 95         image = image.convert('RGB')
 96         name = f'{common.dir}/file/temporary/{str(random.randint(1, 100))}.jpg'
 97         image.save(name)
 98         return name
 99 
100     def get_track(self, x):
101         '''
102         滑块移动轨迹
103         初速度 v =0
104         单位时间 t = 0.2
105         位移轨迹 tracks = []
106         当前位移 ccurrent = 0
107         :param x:
108         :return:
109         '''
110         # 移动轨迹, 即每次移动的距离,为一个列表,总和等于偏移量
111         track = []
112         # 当前位移, 也即记录当前移动了多少距离
113         current = 0
114         # 减速阈值, 也即开始减速的位置,这里设置为偏移量的9/10处开始减速,可以更改
115         # mid = x * 4 / 5
116         # 计算用的时间间隔
117         t = 1
118         # 初始速度
119         v = 1
120 
121         while current < x:
122             # if current < mid:
123             #     # 当前位移小于4/5的偏移量时,加速度为2
124             #     a = 1
125             # else:
126             #     # 当前位移大于4/5的偏移量时,加速度为-3
127             #     a = -3
128             # a = 0
129             # # 初始速度v0
130             # v0 = v
131             # # 本次移动完成之后的速度v = v0 + at
132             # v = v0 + a * t
133             # # 本次移动距离x = v0t + 1/2 * a * t^2
134             # move = v0 * t + 1 / 2 * a * t * t
135             move = v * t
136             # 当前位移, 这里都将move四舍五入取整
137             current += round(move)
138             # 将move的距离放入轨迹列表
139             track.append(round(move))
140             # print("轨迹列表:", track)
141         return track
142 
143     def exchange(self, image):
144         image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
145         for row in range(0, image.shape[0]):
146             for col in range(0, image.shape[1]):
147                 m = image[row][col]/255.00
148                 if m <= 0.2700:
149                     image[row][col] = 0
150                 elif m > 0.2700 and m <= 0.5000:
151                     image[row][col] = (m-0.27)/0.23*127
152                 elif m > 0.5000 and m <= 0.7200:
153                     image[row][col] = (m-0.5)/0.22*255+(0.72-m)/0.22*127
154                 else:
155                     image[row][col] = 255
156         return image
157 
158     def identify_gap(self, bg, tp, out):
159         '''
160         获取缺口位置
161         bg: 背景图片
162         tp: 缺口图片
163         out:输出图片
164         '''
165         # 读取背景图片和缺口图片
166         bg_img = cv2.imread(bg)  # 背景图片
167         tp_img = cv2.imread(tp)  # 缺口图片
168         # time.sleep(1)
169         # bg_img = self.exchange(bg_img)
170         # tp_img = self.exchange(tp_img)
171 
172         # 识别图片边缘
173         bg_edge = cv2.Canny(bg_img, 100, 200)
174         tp_edge = cv2.Canny(tp_img, 100, 200)
175         # 转换图片格式
176         bg_pic = cv2.cvtColor(bg_edge, cv2.COLOR_GRAY2RGB)
177         tp_pic = cv2.cvtColor(tp_edge, cv2.COLOR_GRAY2RGB)
178 
179         # 缺口匹配
180         res = cv2.matchTemplate(bg_pic, tp_pic, cv2.TM_CCOEFF_NORMED)
181         min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)  # 寻找最优匹配
182         # 绘制方框
183         th, tw = tp_pic.shape[:2]
184         tl = max_loc  # 左上角点的坐标
185         br = (tl[0]+tw, tl[1]+th)  # 右下角点的坐标
186         cv2.rectangle(bg_img, tl, br, (0, 0, 255), 2)  # 绘制矩形
187         cv2.imwrite(out, bg_img)  # 保存在本地
188         # 返回缺口的X坐标
189         # print(bg_img.shape[0])
190         # if abs(bg_img.shape[0]-205) > 0:
191         #     tl[0] += bg_img.shape[0]-205
192         return tl[0]
193 
194     def move_slider(self,  track):
195         """根据轨迹列表,拖动滑块到缺口处
196         :param slider: 滑块
197         :param track: 轨迹
198         """
199         ActionChains(self.driver.driver).click_and_hold(
200             self.findelement(self.slider)).perform()
201         for x in track:
202             ActionChains(self.driver.driver).move_by_offset(
203                 xoffset=x, yoffset=0).perform()
204         ActionChains(self.driver.driver).release().perform()
205 
206 
207 class Login_Action(VerificationCode):
208     @ allure.step('输入用户名密码登录')
209     def login(self, userName, userpw):
210         '''
211         输入用户名密码登录
212         :param:userName:用户名
213         :param:userpw:密码
214         '''
215         self.type_name(userName)
216         self.type_pw(userpw)
217         self.drag_slider()
218         # self.quick_slider()
219         self.click_login()
220         assert Navigation(self.driver).get_username() == userName
221 
222     def drag_slider(self):
223         '''
224         第一种方法:移动滑块,完成验证
225         '''
226         self.hover_slider()
227         name1 = self.get_img(self.bgImage)
228         name2 = self.get_img(self.smallImageblocks)
229         out = common.dir+"/file/temporary/out.jpg"
230         x = self.identify_gap(
231             name1, name2, out)
232         print(x)
233         if x > 200:
234             x = x+20  # pass
235         elif x > 150:
236             x = x+16
237         else:
238             x = x+12  # pass
239         tracks = self.get_track(x)
240         self.move_slider(tracks)
241 
242     def quick_slider(self):
243         '''
244          第二种方法:通过接口获取验证成功
245         '''
246         response1 = requests.post(
247             url=settings.Backstage_URL+"/share-auth/getImageVerifyCode")
248         assert response1.status_code == 200
249         content = json.loads(response1.text)
250         for n in range(80, 230, 5):
251             response = requests.get(url=settings.Backstage_URL + "/share-auth-center/validateUnlock",
252                                     params={
253                                         'checkMoveId': content['data']['checkMoveId'], 'xWidth': str(n)}
254                                     )
255             if response.text == 'true':
256                 print(n)
257                 break
258             time.sleep(3)
259         self.set_slider_success()

 

 
 
posted @ 2021-07-19 09:56  ShadowXie  阅读(371)  评论(0编辑  收藏  举报