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()