1. # -*- coding: utf-8 -*-#
    2. # file: BasePage
    3. # Author: ShunZhe
    4. # Date: 2021/1/9
    5. import os
    6. import shutil
    7. import time
    8. from datetime import datetime
    9. from func_timeout.exceptions import FunctionTimedOut
    10. from selenium.webdriver.common.by import By
    11. from selenium.webdriver.support import expected_conditions as EC
    12. from selenium.webdriver.support.wait import WebDriverWait
    13. from common import logger
    14. DelayTime = 1
    15. class BasePage:
    16. def __init__(self, driver):
    17. self.driver = driver
    18. # ----------------------------------------------------
    19. def get_element(self, style, delay=DelayTime, describe=''):
    20. """
    21. :param style: 元素定位
    22. :param delay:
    23. :param describe: 描述用例执行,主要用于日志调试记录,非必填
    24. :return:
    25. """
    26. if "&&" not in style:
    27. raise NameError("语法错误,style缺少'&&'")
    28. else:
    29. by = style.split("&&")[0]
    30. value = style.split("&&")[1]
    31. for i in range(5):
    32. try:
    33. if by == "id":
    34. element = self.driver.find_element_by_id(value)
    35. logger.info('get element: ' + str(value) + '>>' + str(describe))
    36. time.sleep(delay)
    37. elif by == "name":
    38. element = self.driver.find_element_by_name(value)
    39. logger.info('get element: ' + str(value) + '>>' + str(describe))
    40. time.sleep(delay)
    41. elif by == "class":
    42. element = self.driver.find_element_by_class_name(value)
    43. logger.info('get element: ' + str(value) + '>>' + str(describe))
    44. time.sleep(delay)
    45. elif by == "link_text":
    46. element = self.driver.find_element_by_link_text(value)
    47. logger.info('get element: ' + str(value) + '>>' + str(describe))
    48. time.sleep(delay)
    49. elif by == "xpath":
    50. element = self.driver.find_element_by_xpath(value)
    51. logger.info('get element: ' + str(value) + '>>' + str(describe))
    52. time.sleep(delay)
    53. elif by == "css":
    54. element = self.driver.find_element_by_css_selector(value)
    55. logger.info('get element: ' + str(value) + '>>' + str(describe))
    56. time.sleep(delay)
    57. # if self.driver:
    58. # try:
    59. # style_red = 'arguments[0].style.border="2px solid #FF0000"'
    60. # style_green = 'arguments[0].style.border="2px solid #00FF00"'
    61. # style_null = 'arguments[0].style.border=""'
    62. #
    63. # for _ in range(2):
    64. # self.driver.execute_script(style_red, element)
    65. # time.sleep(0.1)
    66. # self.driver.execute_script(style_green, element)
    67. # time.sleep(0.1)
    68. # self.driver.execute_script(style_green, element)
    69. # time.sleep(0.2)
    70. # self.driver.execute_script(style_null, element)
    71. # except WebDriverException:
    72. # pass
    73. return element
    74. except FunctionTimedOut:
    75. element = []
    76. else:
    77. NameError(
    78. "请输入正确的定位元素:'id','name','class','link_text','xpath','css'")
    79. def get_elements(self, style, delay=DelayTime, describe=''):
    80. """
    81. :param style: 元素定位
    82. :param delay:
    83. :param describe: 描述用例执行,主要用于日志调试记录,非必填
    84. :return:
    85. """
    86. if "&&" not in style:
    87. raise NameError("语法错误,style缺少'&&'")
    88. else:
    89. by = style.split("&&")[0]
    90. value = style.split("&&")[1]
    91. for i in range(5):
    92. if by == "id":
    93. element = self.driver.find_elements_by_id(value)
    94. logger.info('get element: ' + str(value) + '>>' + str(describe))
    95. time.sleep(delay)
    96. elif by == "name":
    97. element = self.driver.find_elements_by_name(value)
    98. logger.info('get element: ' + str(value) + '>>' + str(describe))
    99. time.sleep(delay)
    100. elif by == "class":
    101. element = self.driver.find_elements_by_class_name(value)
    102. logger.info('get element: ' + str(value) + '>>' + str(describe))
    103. time.sleep(delay)
    104. elif by == "link_text":
    105. element = self.driver.find_elements_by_link_text(value)
    106. logger.info('get element: ' + str(value) + '>>' + str(describe))
    107. time.sleep(delay)
    108. elif by == "xpath":
    109. element = self.driver.find_elements_by_xpath(value)
    110. logger.info('get element: ' + str(value) + '>>' + str(describe))
    111. time.sleep(delay)
    112. elif by == "css":
    113. element = self.driver.find_elements_by_css_selector(value)
    114. logger.info('get element: ' + str(value) + '>>' + str(describe))
    115. time.sleep(delay)
    116. return element
    117. else:
    118. NameError(
    119. "请输入正确的定位元素:'id','name','class','link_text','xpath','css'")
    120. # ----------------------------------------------------
    121. def click_elem(self, style, describe=''):
    122. """
    123. :param style: 元素定位
    124. :param describe: 描述用例执行,主要用于日志调试记录,非必填
    125. :return:
    126. """
    127. if "&&" not in style:
    128. raise NameError("语法错误,style缺少'&&'")
    129. else:
    130. value = style.split("&&")[1]
    131. element = self.get_element(style).click()
    132. logger.info('click element: ' + str(value) + '>>' + str(describe))
    133. return element
    134. # ----------------------------------------------------
    135. def get_elem_send_keys(self, style, send_key, describe=None):
    136. """
    137. :param style:元素定位
    138. :param send_key:
    139. :param describe: 描述用例执行,主要用于日志调试记录,非必填
    140. :return:
    141. """
    142. if "&&" not in style:
    143. raise NameError("语法错误,style缺少'&&'")
    144. else:
    145. element = self.get_element(style).send_keys(send_key)
    146. logger.info('input keys: ' + str(send_key) + '>>' + str(describe))
    147. return element
    148. # ----------------------------------------------------
    149. def show_wait_visibility(self, style, timeout=20, delay=DelayTime):
    150. """
    151. show_wait_visibility:显示等待函数(该方法需要找到元素,并且该元素也可见)
    152. 提供6种显示等待方法,开发者随使用情况调用
    153. style必须为 XX&&XX的格式,以字符串形式传参
    154. && 前面是定位的方式,后面是定位的元素。例如:id&&#kk
    155. timeout:显示等待超时时间
    156. delay:延迟时间
    157. # presence_of_element_located: 当我们不关心元素是否可见,只关心元素是否存在在页面中。
    158. # visibility_of_element_located: 当我们需要找到元素,并且该元素也可见。
    159. :return:
    160. """
    161. # 显示等待方法导入
    162. if "&&" not in style:
    163. raise NameError("语法错误,style缺少'&&'")
    164. else:
    165. by = style.split("&&")[0]
    166. value = style.split("&&")[1]
    167. if by == "id":
    168. expected = WebDriverWait(self.driver, timeout, 1).until(
    169. EC.visibility_of_element_located((By.ID, value)))
    170. time.sleep(delay)
    171. return expected
    172. elif by == "name":
    173. expected = WebDriverWait(self.driver, timeout, 1).until(
    174. EC.visibility_of_element_located((By.NAME, value)))
    175. time.sleep(delay)
    176. return expected
    177. elif by == "class":
    178. expected = WebDriverWait(self.driver, timeout, 1).until(
    179. EC.visibility_of_element_located((By.CLASS_NAME, value)))
    180. time.sleep(delay)
    181. return expected
    182. elif by == "link_text":
    183. expected = WebDriverWait(self.driver, timeout, 1).until(
    184. EC.visibility_of_element_located((By.LINK_TEXT, value)))
    185. time.sleep(delay)
    186. return expected
    187. elif by == "xpath":
    188. expected = WebDriverWait(self.driver, timeout, 1).until(
    189. EC.visibility_of_element_located((By.XPATH, value)))
    190. time.sleep(delay)
    191. return expected
    192. elif by == "css":
    193. expected = WebDriverWait(self.driver, timeout, 1).until(
    194. EC.visibility_of_element_located((By.CSS_SELECTOR, value)))
    195. time.sleep(delay)
    196. return expected
    197. else:
    198. raise NameError(
    199. "请输入正确的定位元素:'id','name','class','link_text','xpath','css'")
    200. # ----------------------------------------------------
    201. def show_wait_v_until_not(self, style, timeout=20, delay=DelayTime):
    202. if "&&" not in style:
    203. raise NameError("语法错误,style缺少'&&'")
    204. else:
    205. by = style.split("&&")[0]
    206. value = style.split("&&")[1]
    207. if by == "id":
    208. expected = WebDriverWait(self.driver, timeout, 1).until_not(
    209. EC.visibility_of_element_located((By.ID, value)))
    210. time.sleep(delay)
    211. return expected
    212. elif by == "name":
    213. expected = WebDriverWait(self.driver, timeout, 1).until_not(
    214. EC.visibility_of_element_located((By.NAME, value)))
    215. time.sleep(delay)
    216. return expected
    217. elif by == "class":
    218. expected = WebDriverWait(self.driver, timeout, 1).until_not(
    219. EC.visibility_of_element_located((By.CLASS_NAME, value)))
    220. time.sleep(delay)
    221. return expected
    222. elif by == "link_text":
    223. expected = WebDriverWait(self.driver, timeout, 1).until_not(
    224. EC.visibility_of_element_located((By.LINK_TEXT, value)))
    225. time.sleep(delay)
    226. return expected
    227. elif by == "xpath":
    228. expected = WebDriverWait(self.driver, timeout, 1).until_not(
    229. EC.visibility_of_element_located((By.XPATH, value)))
    230. time.sleep(delay)
    231. return expected
    232. elif by == "css":
    233. expected = WebDriverWait(self.driver, timeout, 1).until_not(
    234. EC.visibility_of_element_located((By.CSS_SELECTOR, value)))
    235. time.sleep(delay)
    236. return expected
    237. else:
    238. raise NameError(
    239. "请输入正确的定位元素:'id','name','class','link_text','xpath','css'")
    240. # ----------------------------------------------------
    241. def show_wait_presence(self, style, timeout=20, delay=DelayTime):
    242. """
    243. show_wait_presence:显示等待函数(该方法不关心元素是否可见,只关心元素是否存在在页面中)
    244. 提供6种显示等待方法,开发者随使用情况调用
    245. style必须为 XX&&XX的格式,以字符串形式传参
    246. && 前面是定位的方式,后面是定位的元素。例如:id&&#kk
    247. timeout:显示等待超时时间
    248. delay:延迟时间
    249. # presence_of_element_located: 当我们不关心元素是否可见,只关心元素是否存在在页面中。
    250. # visibility_of_element_located: 当我们需要找到元素,并且该元素也可见。
    251. :return:
    252. """
    253. # 显示等待方法导入
    254. if "&&" not in style:
    255. raise NameError("语法错误,style缺少'&&'")
    256. else:
    257. by = style.split("&&")[0]
    258. value = style.split("&&")[1]
    259. if by == "id":
    260. expected = WebDriverWait(self.driver, timeout, 1).until(EC.presence_of_element_located((By.ID, value)))
    261. time.sleep(delay)
    262. return expected
    263. elif by == "name":
    264. expected = WebDriverWait(self.driver, timeout, 1).until(
    265. EC.presence_of_element_located((By.NAME, value)))
    266. time.sleep(delay)
    267. return expected
    268. elif by == "class":
    269. expected = WebDriverWait(self.driver, timeout, 1).until(
    270. EC.presence_of_element_located((By.CLASS_NAME, value)))
    271. time.sleep(delay)
    272. return expected
    273. elif by == "link_text":
    274. expected = WebDriverWait(self.driver, timeout, 1).until(
    275. EC.presence_of_element_located((By.LINK_TEXT, value)))
    276. time.sleep(delay)
    277. return expected
    278. elif by == "xpath":
    279. expected = WebDriverWait(self.driver, timeout, 1).until(
    280. EC.presence_of_element_located((By.XPATH, value)))
    281. time.sleep(delay)
    282. return expected
    283. elif by == "css":
    284. expected = WebDriverWait(self.driver, timeout, 1).until(
    285. EC.presence_of_element_located((By.CSS_SELECTOR, value)))
    286. time.sleep(delay)
    287. return expected
    288. else:
    289. raise NameError(
    290. "请输入正确的定位元素:'id','name','class','link_text','xpath','css'")
    291. # ----------------------------------------------------
    292. def show_wait_p_until_not(self, style, timeout=20, delay=DelayTime):
    293. if "&&" not in style:
    294. raise NameError("语法错误,style缺少'&&'")
    295. else:
    296. by = style.split("&&")[0]
    297. value = style.split("&&")[1]
    298. if by == "id":
    299. expected = WebDriverWait(self.driver, timeout, 1).until_not(
    300. EC.presence_of_element_located((By.ID, value)))
    301. time.sleep(delay)
    302. return expected
    303. elif by == "name":
    304. expected = WebDriverWait(self.driver, timeout, 1).until_not(
    305. EC.presence_of_element_located((By.NAME, value)))
    306. time.sleep(delay)
    307. return expected
    308. elif by == "class":
    309. expected = WebDriverWait(self.driver, timeout, 1).until_not(
    310. EC.presence_of_element_located((By.CLASS_NAME, value)))
    311. time.sleep(delay)
    312. return expected
    313. elif by == "link_text":
    314. expected = WebDriverWait(self.driver, timeout, 1).until_not(
    315. EC.presence_of_element_located((By.LINK_TEXT, value)))
    316. time.sleep(delay)
    317. return expected
    318. elif by == "xpath":
    319. expected = WebDriverWait(self.driver, timeout, 1).until_not(
    320. EC.presence_of_element_located((By.XPATH, value)))
    321. time.sleep(delay)
    322. return expected
    323. elif by == "css":
    324. expected = WebDriverWait(self.driver, timeout, 1).until_not(
    325. EC.presence_of_element_located((By.CSS_SELECTOR, value)))
    326. time.sleep(delay)
    327. return expected
    328. else:
    329. raise NameError(
    330. "请输入正确的定位元素:'id','name','class','link_text','xpath','css'")
    331. @staticmethod
    332. def get_datetime_str():
    333. """获取日期字符串"""
    334. datetime_str = datetime.now().strftime('%Y%m%d%H%M%S%f')
    335. return datetime_str
    336. @classmethod
    337. def create_folder(cls, folder_path, folder):
    338. """新建文件夹并返回文件路径"""
    339. work_file = os.path.join(folder_path, folder)
    340. if not os.path.exists(work_file):
    341. os.mkdir(work_file)
    342. return work_file
    343. """
    344. 文件操作
    345. """
    346. @classmethod
    347. def clear_files(cls, path):
    348. """清除文件夹中的数据"""
    349. for root, dirs, files in os.walk(path):
    350. for f in files:
    351. os.unlink(os.path.join(root, f))
    352. for d in dirs:
    353. shutil.rmtree(os.path.join(root, d))
    1. # -*- coding: utf-8 -*-#
    2. # file: web_page
    3. # Author: ShunZhe
    4. # Date: 2021/1/20
    5. import os
    6. import platform
    7. import time
    8. import pyautogui
    9. import pyperclip
    10. from airtest import aircv
    11. from selenium.webdriver import ActionChains
    12. from selenium.webdriver.common.keys import Keys
    13. from common import logger
    14. from lib.base_page import BasePage
    15. from lib.ocv.cv import Template
    16. from lib.ocv.error import TargetNotFoundError
    17. from lib.ocv.settings import Settings
    18. from lib.path import Path
    19. DelayTime = 1
    20. pyautogui.PAUSE = 1 # 调用在动作执行后暂停的秒数
    21. pyautogui.FAILSAFE = True # 启动自动防故障功能,将鼠标移动到左上坐标(0,0),抛出failSafeException异常
    22. class Webpage(BasePage):
    23. """
    24. web端页面基类,提供web端定位元素的api和各种操作元素的api,包括图像识别的方法
    25. """
    26. def get(self, url):
    27. """
    28. 打开连接
    29. """
    30. self.driver.get(url)
    31. logger.info("open url: " + url)
    32. def switch_to_iframe(self, frame_id):
    33. """切换进入iframe页面"""
    34. logger.info('switch to the iframe')
    35. self.driver.switch_to_frame(frame_id)
    36. def switch_to_default_content(self):
    37. """从iframe切回主界面"""
    38. self.driver.switch_to_default_content()
    39. logger.info("switch to default content")
    40. def get_current_url(self):
    41. """
    42. 获取当前窗口url地址
    43. """
    44. return self.driver.current_url
    45. def get_elem_text(self, style):
    46. """
    47. 获取文本
    48. :param style:
    49. :return:
    50. """
    51. return self.get_element(style).text
    52. def get_elem_attribute(self, style, val):
    53. """
    54. 获取某个元素值
    55. :param style:
    56. :param val: 获取的属性
    57. :return:
    58. """
    59. return self.get_element(style).get_attribute(val)
    60. @classmethod
    61. def upload(cls, file):
    62. """
    63. 上传文件,兼容mac和windows系统
    64. :param file:上传文件路径
    65. :return:
    66. """
    67. if platform.system() == "Darwin":
    68. # mac系统
    69. x_dim, y_dim = pyautogui.size()
    70. pyautogui.click(x_dim // 2, y_dim // 2, duration=0.5)
    71. pyautogui.click(x_dim // 2 + 50, y_dim // 2 + 50, duration=0.5)
    72. time.sleep(3)
    73. pyautogui.hotkey('command', 'shift', 'g')
    74. time.sleep(2)
    75. pyperclip.copy('/')
    76. pyautogui.hotkey('command', 'v')
    77. time.sleep(1)
    78. pyautogui.hotkey('command', 'a')
    79. pyautogui.hotkey('command', 'delete')
    80. time.sleep(1)
    81. pyperclip.copy(file)
    82. pyautogui.hotkey('command', 'v')
    83. elif platform.system() == "Windows":
    84. # windows系统
    85. time.sleep(3)
    86. pyperclip.copy(file)
    87. pyautogui.hotkey('ctrl', 'v')
    88. time.sleep(1)
    89. pyautogui.press('enter', presses=2)
    90. time.sleep(2)
    91. def switch_to_last_window(self):
    92. """
    93. 切换到当前浏览器最新打开的窗口
    94. """
    95. all_h = self.driver.window_handles
    96. return self.driver.switch_to.window(all_h[-1])
    97. def switch_to_first_window(self):
    98. """
    99. 切换到当前浏览器首次打开的窗口
    100. """
    101. all_h = self.driver.window_handles
    102. return self.driver.switch_to.window(all_h[0])
    103. def get_elements_counts(self, style):
    104. """
    105. 获取一组元素并返回元素个数
    106. """
    107. sum_counts = self.get_elements(style, describe="获取一组元素")
    108. logger.info('获取一组元素个数:' + str(len(sum_counts)))
    109. return len(sum_counts)
    110. def select_all(self, style):
    111. """
    112. 模拟全选ctrl+a
    113. """
    114. if platform.system().lower() == "darwin":
    115. self.get_element(style).send_keys(Keys.COMMAND, "a")
    116. else:
    117. self.get_element(style).send_keys(Keys.CONTROL, "a")
    118. logger.info("select_all:" + str(style.split("&&")[1]))
    119. def keyboard_cut(self, style):
    120. """
    121. 模拟剪切ctrl+x
    122. """
    123. if platform.system().lower() == "darwin":
    124. self.get_element(style).send_keys(Keys.COMMAND, "x")
    125. else:
    126. self.get_element(style).send_keys(Keys.CONTROL, "x")
    127. logger.info("keyboard_cut:" + str(style.split("&&")[1]))
    128. def keyboard_copy(self, style):
    129. """
    130. 模拟复制ctrl+c
    131. """
    132. if platform.system().lower() == "darwin":
    133. self.get_element(style).send_keys(Keys.COMMAND, "c")
    134. else:
    135. self.get_element(style).send_keys(Keys.CONTROL, "c")
    136. logger.info("keyboard_copy:" + str(style.split("&&")[1]))
    137. def keyboard_paste(self, style):
    138. """
    139. 模拟粘贴ctrl+v
    140. """
    141. if platform.system().lower() == "darwin":
    142. self.get_element(style).send_keys(Keys.COMMAND, "v")
    143. else:
    144. self.get_element(style).send_keys(Keys.CONTROL, "v")
    145. logger.info("keyboard_paste:" + str(style.split("&&")[1]))
    146. def keyboard_delete(self, style):
    147. """
    148. 模拟delete键
    149. """
    150. self.get_element(style).send_keys(Keys.DELETE)
    151. logger.info("keyboard_delete:" + str(style.split("&&")[1]))
    152. def keyboard_enter(self, style):
    153. """
    154. 模拟回车键
    155. """
    156. self.get_element(style).send_keys(Keys.ENTER)
    157. logger.info("keyboard_enter:" + str(style.split("&&")[1]))
    158. """
    159. 鼠标操作
    160. """
    161. def move_to_element(self, style):
    162. """
    163. Moving the mouse to the middle of an element
    164. """
    165. ActionChains(self.driver).move_to_element(self.get_element(style)).perform()
    166. logger.info("focus element:" + str(style.split("&&")[1]))
    167. def right_click(self, style):
    168. """右键"""
    169. ActionChains(self.driver).context_click(self.get_element(style)).perform()
    170. logger.info("right click element:" + str(style.split("&&")[1]))
    171. def move_by_offset(self, x=0, y=0):
    172. """按住鼠标移动"""
    173. e = ActionChains(self.driver).move_by_offset(x, y)
    174. logger.info("click_and_hold to the coordinate is ({}, {})".format(x, y))
    175. return e
    176. def click_and_hold(self, style):
    177. """按住鼠标"""
    178. res = ActionChains(self.driver).click_and_hold(on_element=self.get_element(style))
    179. logger.info("click and hold the mouse")
    180. return res
    181. def click_after_focus(self, focus_style, style):
    182. """
    183. hover元素并点击操作
    184. :param focus_style: hover的元素
    185. :param style: 点击的元素
    186. :return:
    187. """
    188. focus_elem = self.get_element(focus_style)
    189. click_elem = self.get_element(style)
    190. ActionChains(self.driver).move_to_element(focus_elem).click(click_elem).perform()
    191. def scroll_down(self, style, amount_to_scroll=-200):
    192. """
    193. 向下滚动指定格数
    194. style:元素定位
    195. amount_to_scroll:滚动格数
    196. eg:
    197. scroll_down(style, -10) # 向下滚动10格
    198. """
    199. self.move_to_element(style)
    200. time.sleep(2)
    201. if abs(amount_to_scroll) > 200:
    202. for i in range(abs(amount_to_scroll) // 200):
    203. time.sleep(2)
    204. pyautogui.scroll(-200)
    205. def scroll_up(self, style, amount_to_scroll=200):
    206. """
    207. 向上滚动指定格数
    208. style:元素定位
    209. amount_to_scroll:滚动格数
    210. eg:
    211. scroll_down(style, 10) # 向上滚动10格
    212. """
    213. self.move_to_element(style)
    214. time.sleep(2)
    215. if amount_to_scroll > 200:
    216. for i in range(int(amount_to_scroll) // 200):
    217. time.sleep(2)
    218. pyautogui.scroll(200)
    219. """
    220. js操作浏览器
    221. """
    222. def js_click(self, style, delay=DelayTime, index=0, describe=''):
    223. """
    224. :param style: 元素定位
    225. :param delay:
    226. :param index: 获取定位元素项数,默认为0,第一项
    227. :param describe: 描述用例执行,主要用于日志调试记录,非必填
    228. :return:
    229. """
    230. if "&&" not in style:
    231. raise NameError("语法错误,style缺少'&&'")
    232. else:
    233. by = style.split("&&")[0]
    234. value = style.split("&&")[1]
    235. if by == "css":
    236. js = """document.querySelectorAll('{css}')[{index}].click();""".format(css=value, index=index)
    237. self.driver.execute_script(js)
    238. time.sleep(delay)
    239. logger.info("click element by js:" + value + '>>' + describe)
    240. def js_get_attribute(self, style, attribute, index=0, describe=''):
    241. """
    242. 获取指定元素属性
    243. :param attribute: 被获取元素
    244. :param style: 元素定位
    245. :param index: 获取定位元素项数,默认为0,第一项
    246. :param describe: 描述用例执行,主要用于日志调试记录,非必填
    247. """
    248. if "&&" not in style:
    249. raise NameError("语法错误,style缺少'&&'")
    250. else:
    251. by = style.split("&&")[0]
    252. value = style.split("&&")[1]
    253. if by == "css":
    254. time.sleep(2)
    255. js = """return document.querySelectorAll('{css}')[{index}].getAttribute('{attr}');""". \
    256. format(css=value, index=index, attr=attribute)
    257. return self.driver.execute_script(js)
    258. logger.info("get_attribute by js:" + value + '>>' + describe)
    259. def js_update_inner_text(self, style, text, index=0, describe=''):
    260. """
    261. 修改文本框
    262. :param text:
    263. :param style:
    264. :param index: 获取定位元素项数,默认为0,第一项
    265. :param describe: 描述用例执行,主要用于日志调试记录,非必填
    266. """
    267. if "&&" not in style:
    268. raise NameError("语法错误,style缺少'&&'")
    269. else:
    270. by = style.split("&&")[0]
    271. value = style.split("&&")[1]
    272. if by == "css":
    273. js = """var elm = document.querySelectorAll('{css}')[{index}];
    274. elm.innerText='{text}';""".format(css=value, index=index, text=text)
    275. self.driver.execute_script(js)
    276. logger.info("update text by js:" + value + '>>' + describe)
    277. def js_get_text_content(self, style, index=0, describe=''):
    278. """
    279. 获取文本
    280. :param style:
    281. :param index: 获取定位元素项数,默认为0,第一项
    282. :param describe: 描述用例执行,主要用于日志调试记录,非必填
    283. """
    284. if "&&" not in style:
    285. raise NameError("语法错误,style缺少'&&'")
    286. else:
    287. by = style.split("&&")[0]
    288. value = style.split("&&")[1]
    289. if by == "css":
    290. time.sleep(2)
    291. js = """return document.querySelectorAll('{css}')[{index}].textContent;""".format(css=value,
    292. index=index)
    293. return self.driver.execute_script(js)
    294. logger.info("get textContent by js:" + value + '>>' + describe)
    295. def clear_local_storage(self):
    296. """清除浏览器localStorage"""
    297. js = """window.localStorage.clear();"""
    298. self.driver.execute_script(js)
    299. logger.info("clear localStorage successful~")
    300. def add_cookies_and_refresh(self, cookies):
    301. """添加浏览器cookies"""
    302. self.driver.delete_all_cookies()
    303. self.driver.add_cookie(cookies)
    304. self.driver.refresh()
    305. time.sleep(2)
    306. logger.info("add cookies successful and refresh the browser")
    307. @staticmethod
    308. def get_screen_size():
    309. """
    310. 获取当前屏幕分辨率
    311. """
    312. screen_size = pyautogui.size()
    313. return screen_size
    314. def full_screenshot(self):
    315. """
    316. 全屏幕截图
    317. """
    318. screenshot_path = os.path.abspath(Path().SCREENSHOT_PATH)
    319. if not os.path.exists(screenshot_path):
    320. os.mkdir(screenshot_path)
    321. time_str = self.get_datetime_str()
    322. file_path = f'{screenshot_path}/{time_str}.png'
    323. pyautogui.screenshot(file_path)
    324. return file_path
    325. def get_cv_obj(self):
    326. """根据图片路径,将图片处理为cv2的图片处理格式"""
    327. file_path = self.full_screenshot()
    328. cv_obj = aircv.imread(file_path)
    329. return cv_obj
    330. def _try_log_screen(self, screen=None):
    331. """
    332. 记录图像识别的屏幕截图
    333. Args:
    334. screen: screenshot to be saved
    335. Returns:
    336. None
    337. """
    338. # 没有默认配置,则使用临时目录存放识别的图片
    339. if not Settings.SS_DIR:
    340. Settings.SS_DIR = Path().TMP_IMG_PATH
    341. if screen is None:
    342. screen = self.get_cv_obj()
    343. datetime_str = self.get_datetime_str()
    344. filename = f"{datetime_str}.jpg"
    345. filepath = os.path.join(Settings.SS_DIR, filename)
    346. aircv.imwrite(filepath, screen)
    347. def get_template(self, filename, threshold=None, record_pos=None, resolution=(), rgb=False):
    348. """picture as touch/swipe/wait/exists target and extra info for cv match"""
    349. if not resolution:
    350. resolution = self.get_screen_size()
    351. if not os.path.exists(filename):
    352. filename = os.path.join(Settings.IMG_DIR_PATH, filename)
    353. logger.info(f"查找图片: {filename}")
    354. template = Template(filename, threshold=threshold, record_pos=record_pos, resolution=resolution, rgb=rgb)
    355. return template
    356. def loop_find(self, filename, timeout=Settings.FIND_TIMEOUT, threshold=None, interval=0.5, intervalfunc=None):
    357. """
    358. 在当前屏幕查找预期图片,直到超时
    359. Args:
    360. filename: mage name or image file path
    361. timeout: time interval how long to look for the image template
    362. threshold: default is None
    363. interval: sleep interval before next attempt to find the image template
    364. intervalfunc: function that is executed after unsuccessful attempt to find the image template
    365. Raises:
    366. TargetNotFoundError: when image template is not found in screenshot
    367. Returns:
    368. TargetNotFoundError if image template not found, otherwise returns the position where the image template has
    369. been found in screenshot
    370. """
    371. query = self.get_template(filename, threshold=threshold)
    372. start_time = time.time()
    373. while True:
    374. screen = self.get_cv_obj()
    375. query.resolution = self.get_resolution(screen)
    376. if screen is None:
    377. logger.warn("Screen is None, may be locked")
    378. else:
    379. if threshold:
    380. query.threshold = threshold
    381. match_pos = query.match_in(screen)
    382. if match_pos:
    383. self._try_log_screen(screen)
    384. return match_pos
    385. if intervalfunc is not None:
    386. intervalfunc()
    387. # 超时则raise,未超时则进行下次循环:
    388. if (time.time() - start_time) > timeout:
    389. self._try_log_screen(screen)
    390. raise TargetNotFoundError('Picture %s not found in screen' % query)
    391. else:
    392. time.sleep(interval)
    393. @staticmethod
    394. def get_resolution(img):
    395. h, w = img.shape[:2]
    396. return w, h
    397. @staticmethod
    398. def click_mouse_coordinate(*pos):
    399. """点击鼠标坐标"""
    400. # 关闭安全特性
    401. pyautogui.FAILSAFE = False
    402. pyautogui.moveTo(*pos)
    403. # 鼠标双击
    404. pyautogui.doubleClick()
    405. def touch(self, filename, threshold=Settings.THRESHOLD, times=1, timeout=Settings.FIND_TIMEOUT, **kwargs):
    406. """
    407. 点击识别到的图片位置
    408. :param threshold: 识别图片的匹配度,默认0.8
    409. :param filename: 识别图片的文件名或文件路径,直接传文件名,会拼接上ocv/settings文件配置的IMG_DIR_PATH路径
    410. :param times: how many touches to be performed
    411. :param timeout: 查找图片最多等待时间
    412. :param kwargs: platform specific `kwargs`, please refer to corresponding docs
    413. :return: finial position to be clicked
    414. :platforms: Android, iOS
    415. 用法:
    416. 页面类继承MobilePage
    417. self.touch('img_name.png', threshold=0.8)
    418. """
    419. _pos = self.loop_find(filename, timeout=timeout, threshold=threshold)
    420. logger.info(f'{filename},获取到的图像坐标位置:{_pos}')
    421. for _ in range(times):
    422. if platform.system() == 'Darwin':
    423. pos = (_pos[0] / 2, _pos[1] / 2)
    424. self.click_mouse_coordinate(pos)
    425. else:
    426. self.click_mouse_coordinate(_pos)
    427. time.sleep(1)
    428. return _pos
    429. def screenshots_and_return_Coordinates(self, folder, filename, _x, _y, width, height, threshold=Settings.THRESHOLD,
    430. timeout=Settings.FIND_TIMEOUT):
    431. """截图并返回截图坐标"""
    432. folder_file = self.create_folder(Path().PLAYER_PATH, folder)
    433. time.sleep(4)
    434. pyautogui.moveTo(_x, _y, duration=0.1)
    435. if platform.system() == "Darwin":
    436. image = pyautogui.screenshot(region=(_x * 2, _y * 2, width * 2, height * 2))
    437. image.save(os.path.join(folder_file, filename))
    438. else:
    439. image = pyautogui.screenshot(region=(_x, _y, width, height))
    440. image.save(os.path.join(folder_file, filename))
    441. logger.info("Picture {} saved successfully!传入参数x坐标{},y坐标{},宽{},高{}".format(filename, _x, _y, width, height))
    442. start_time = time.time()
    443. if time.time() - start_time > timeout:
    444. raise TargetNotFoundError("Picture is not Found!")
    445. else:
    446. logger.info(" The image {} has been identified".format(filename))
    447. _pos = pyautogui.locateCenterOnScreen(os.path.join(folder_file, filename), confidence=threshold)
    448. if platform.system() == 'Darwin':
    449. _pos = (_pos[0] / 2, _pos[1] / 2)
    450. else:
    451. _pos = _pos
    452. logger.info("图片坐标:{}".format(_pos))
    453. return _pos
    454. def is_img_exists(self, filename, threshold=Settings.THRESHOLD_STRICT, timeout=Settings.FIND_TIMEOUT, msg=""):
    455. """
    456. 验证预期图片是否存在当前屏幕
    457. :param threshold: 识别图片的匹配度,默认0.8
    458. :param filename: 识别图片的文件名或文件路径,直接传文件名,会拼接上ocv/settings文件配置的IMG_DIR_PATH路径
    459. :param timeout: 查找图片最多等待时间
    460. :param msg: short description of assertion, it will be recorded in the report
    461. :raise AssertionError: if assertion fails
    462. :return: coordinates of the target
    463. """
    464. try:
    465. pos = self.loop_find(filename, timeout=timeout, threshold=threshold)
    466. logger.info(f'{filename}获取到的图像坐标位置:{pos}')
    467. return True
    468. except TargetNotFoundError:
    469. logger.error(f"没有匹配到图像:{filename}, 匹配度设置:{threshold} message: {msg}")
    470. return False
    471. def is_element_exists(self, style):
    472. """检查元素是否存在"""
    473. try:
    474. self.get_element(style)
    475. logger.info(style.split("&&")[1] + " element exists")
    476. return True
    477. except:
    478. logger.info(style.split("&&")[1] + " element does not exist")
    479. return False