class ProfilePage(WebPage): '''个人资料页 ''' ui_map = { '用户名': XPath('//*[@id="home-container"]/div[2]/div[2]/span/span[1]'), 'err_msg': XPath('/html/body/div[3]/div/p') }
def __init__(self, root, locator): ControlContainer.__init__(self) from qt4w.__init__ import XPath from qt4w.util import WebElementAttributes, WebElementStyles if isinstance(root, WebPage): self._page = root else: self._page = root.page self._webview = self._page._webview self._webdriver = self._page._webdriver self._root = root if isinstance(root, WebPage): self._locators = root._locator + XPath(locator).break_frames() elif isinstance(root, FrameElement): loc = XPath(locator).break_frames() self._locators = root._locators + loc else: self._locators = root._locators[:-1] self._locators += XPath(root._locators[-1] + locator).break_frames() self._attrs = WebElementAttributes(self._getattr, self._setattr, self._listattr) self._styles = WebElementStyles(self._getstyle)
class ProfilePage(WebPage): '''个人资料页 ''' ui_map = { '用户名': XPath('//div[@id="name"]'), '性别': XPath('//div[@id="sex"]'), '年龄': XPath('//div[@id="age"]'), '公司': XPath('//div[@id="company"]') }
class DemoWebPage(WebPage): '''Demo Web页面 ''' ui_map = { '标题': XPath('//h2'), 'qt4a_source_code': { 'type': WebElement, 'locator': XPath('//div[@id="qt4a_code"]/a'), } #'qt4a_source_code':XPath('//div[@id="qt4a_code"]/a'), #如果type为WebElement也可直接简化为该写法,所以此时qt4a_source_code这么定义也可以 }
class QQ007WebPage(WebPage): ui_map = { "体验用户": XPath('//a[text()="体验用户"]'), "可疑用户": XPath('//a[text()="可疑用户"]'), "恶意用户": XPath('//a[text()="恶意用户"]'), "体验验证码": XPath('//button[@id="code"]'), "验证码IFrame": { "type": TencentCaptchaFrameElement, "locator": XPath('//iframe[@id="tcaptcha_iframe"]'), }, }
def __init__(self): ui_map = { "test": {'type': WebElement, 'locator': XPath("//div[@id='test']"), 'ui_map': {'close': {'type': WebElement, 'locator': XPath("//div[@class='close']"), }, }, } } self.view = TestWebView("testbrowser") super(TestPage, self).__init__(self.view, wait_for_ready=False) self.update_ui_map(ui_map)
class MiniProgramTextPage(WXMPPage): '''小程序text组件界面 ''' ui_map = { '文本区域': XPath('//wx-text/span[2]'), '添加一行': XPath('//wx-button[text()="add line"]'), '移除一行': XPath('//wx-button[text()="remove line"]') } def add_line(self): self.control('添加一行').click() def remove_line(self): self.control('移除一行').click()
class LoginPage(WebPage): '''Demo页面 ''' ui_map = { 'username': { 'type': InputElement, 'locator': XPath( '//*[@id="app"]/div/div[2]/div/div[2]/form/div[1]/div/div/input' ) }, 'password': { 'type': InputElement, 'locator': XPath( '//*[@id="app"]/div/div[2]/div/div[2]/form/div[2]/div/div/input' ) }, 'login': XPath('//*[@id="app"]/div/div[2]/div/div[2]/form/button'), } def set_username(self, username): '''输入用户名 ''' self.control('username').value = username def set_password(self, password): '''输入密码 ''' self.control('password').value = password def submit(self): '''点击登录 ''' self.control('login').click() def login(self, username, password): self.control('username').value = username self.control('password').value = password self.control('login').click()
class DemoPage(WebPage): '''Demoapp web页面 ''' ui_map = { 'title': { 'type': WebElement, 'locator': XPath('//div[@class="panel-heading"]') }, 'name': { 'type': InputElement, 'locator': XPath('//input[@id="name"]') }, 'female': { 'type': WebElement, 'locator': XPath('//input[@value="female"]') }, 'male': { 'type': WebElement, 'locator': XPath('//input[@value="male"]') }, 'age': { 'type': SelectElement, 'locator': XPath('//select[@id="age"]') }, 'company': { 'type': InputElement, 'locator': XPath('//input[@id="company"]') }, 'submit': { 'type': WebElement, 'locator': XPath('//button[@id="submit"]') }, } #设置姓名 def set_name(self, name): print self.control('name').exist() self.control('name').value = name #设置性别 def set_female(self): self.control('female').click() def set_male(self): self.control('male').click() #设置姓名 def set_age(self, age): self.control('age').selection = age #设置公司名 def set_company(self, company): self.control('company').value = company #提交结果 def submit(self): self.control("submit").click()
def __init__(self,root="",locator=[]): ui_map = { "test": {'type': type(self), 'locator': XPath("//div[@id='test']"), } } self.view = TestWebView("testbrowser") self.test = TestPage() super(TestElement, self).__init__(self.test,"//div[@id='test']") self.test.get_webview().set_attribute("","value", "test") self.update_ui_map(ui_map)
class TencentCaptchaPage(WebPage): ui_map = { "背景图片": XPath('//img[@id="slideBg"]'), "滑块图片": XPath('//img[@id="slideBlock"]'), "滑块": XPath('//div[@id="tcaptcha_drag_thumb"]'), "刷新1": XPath('//div[@id="reload"]'), "刷新2": XPath('//div[@id="e_reload"]'), } def validate(self): bg_url = self.control("背景图片").src response = requests.get(bg_url) save_path = "bg.jpg" with open(save_path, "wb") as fp: fp.write(response.content) img = Image.open(save_path) img = image.binarize(img) img = image.remove_discrete_points(img) left, top = image.locate_shadow_area(img) if left <= 0 or top <= 0: if self.control('刷新1').visible: self.control("刷新1").click() else: self.control("刷新2").click() return self.validate() rect1 = self.control("背景图片").rect rect2 = self.control("滑块图片").rect print(rect1, rect2, left, top) print(img.size, left, top) rect = self.control("滑块").rect bypass.smart_drag( self._webview, rect[0] + rect[2] / 2, rect[1] + rect[3] / 2, rect[0] + rect[2] / 2 + left - (rect2[0] - rect1[0]) - 30, rect[1] + rect[3] / 2, )
def test_break_frame(self): xp = XPath('//div[@id="google_shimpl"]//div[text()="test"]') steps = xp.break_frames() self.assertEqual('//div[@id="google_shimpl"]//div[text()="test"]', steps[0]) xp = XPath('//iframe[@id="google_shimpl"]//div[text()="test"]') steps = xp.break_frames() self.assertEqual('//iframe[@id="google_shimpl"]', steps[0])
class MiniProgramComponentPage(WXMPPage): '''微信官方小程序示例主页面 ''' ui_map = { '视图容器区域': { 'type': WebElement, 'locator': XPath('//wx-view[@class="kind-list-item"][1]'), 'ui_map': { '标题': XPath('//*[@id="view"]'), 'view': XPath('//*[text()="view"]'), 'scroll-view': XPath('//*[text()="scroll-view"]') } }, '组件分类': { 'type': ui_list(WebElement), 'locator': XPath('//wx-view[@class="kind-list-item"]'), 'ui_map': { '标题': XPath('//wx-view[@class="kind-list-text"]'), '组件列表': { 'type': ui_list(WebElement), 'locator': XPath('//wx-navigator[@class="navigator"]'), 'ui_map': { '名称': XPath('/wx-view[@class="navigator-text"]') } } } } } def open_component_page(self, category, name): '''打开组件页面 ''' for cat in self.control('组件分类'): if cat.control('标题').inner_text == category: rect1 = cat.rect rect2 = cat.control('标题').rect if rect1[3] - rect2[3] < 200: # 需要展开 cat.click() for comp in cat.control('组件列表'): if comp.control('名称').inner_text == name: comp.click() return else: raise RuntimeError('Find component %s failed' % name) else: raise RuntimeError('Find component type %s failed' % category)
class DemoPage(WebPage): '''Demo页面 ''' ui_map = { 'title': XPath('//div[@class="panel-heading"]'), 'name': {'type': InputElement, 'locator': XPath('//input[@id="name"]')}, 'female': XPath('//input[@value="female"]'), 'male': XPath('//input[@value="male"]'), 'age': {'type': SelectElement, 'locator': XPath('//select[@id="age"]')}, 'company': {'type': InputElement, 'locator': XPath('//input[@id="company"]')}, 'submit': XPath('//button[@id="submit"]'), } def set_name(self, name): '''设置姓名 ''' self.control('name').value = name def set_female(self): '''设置性别为女性 ''' self.control('female').click() def set_male(self): '''设置性别为男性 ''' self.control('male').click() def set_age(self, age): '''设置年龄 ''' self.control('age').selection = age def set_company(self, company): '''设置公司名 ''' self.control('company').value = company def submit(self): '''提交 ''' self.control("submit").click()
def get_elements(self, locator, elem_cls=None): '''在页面中查找元素,返回包含所有匹配的元素的列表 :param locator: 元素的xpath路径 :type locator: string或XPath :paran elem_cls: 返回的元素类型 :type elem_cls: class ''' from qt4w.util import LazyDict locators = self._locator[:] child_locators = XPath(locator).break_frames() locators.extend(child_locators) elem_count = self._webdriver.get_element_count(locators) def get_elem(index): if len(child_locators) == 1: loc = '(%s)[%d]' % (locator, index + 1) else: loc = '%s(%s)[%d]' % (''.join( child_locators[:-1]), child_locators[-1], index + 1) return self.get_element(loc, elem_cls) return LazyDict(get_elem, lister=lambda: xrange(elem_count))
def __init__(self, root, locator): loc = XPath(locator).break_frames()[-1] if not ('/iframe' in loc or '/frame' in loc): raise ValueError("Not a Frame nor IFrame: '%s'" % locator) super(FrameElement, self).__init__(root, locator) self._frame_page = None
def test_break_frame(self): xp = XPath('//div[@id="google_shimpl"]//div[text()="test"]') steps = xp.break_frames() self.assertEqual('//div[@id="google_shimpl"]//div[text()="test"]', steps[0]) xp = XPath('//iframe[@id="google_shimpl"]//div[text()="test"]') steps = xp.break_frames() self.assertEqual('//iframe[@id="google_shimpl"]', steps[0]) xp = XPath('(//iframe[@id="google_shimpl"])//div[text()="test"]') steps = xp.break_frames() self.assertEqual('(//iframe[@id="google_shimpl"])', steps[0]) xp = XPath( '//frame[@id="main"]//iframe[@id="mainwindow"]//I[@class="spr nav1"]' ) steps = xp.break_frames() self.assertEqual('//frame[@id="main"]', steps[0])
def test_node(self): xp = XPath('//div[@id="google_shimpl"]') self.assertEqual("div", xp.Nodetest) xp = XPath('//div[@id="google_shimpl"]//div[text()="test"]') self.assertEqual("div", xp.Nodetest)
class MiniProgramSearchPage(WebPage): '''小程序搜索结果页面 ''' ui_map = {'推荐搜索列表': {'type': ui_list(WebElement), 'locator': XPath('//div[@class="sug_wrp"]/div[@class="weui_cells"]/div[@class="weui_cell"]'), 'ui_map': { '小程序名': XPath('//p[@class="sug_text"]') } }, '使用过的小程序列表': {'type': ui_list(WebElement), 'locator': XPath('//div[@class="weui_cells"]/div[@class="weui_cell search_item sug_biz"]'), 'ui_map': {'小程序名': XPath('//em[@class="highlight"]') } }, '搜索历史列表': { 'type': ui_list(WebElement), 'locator': XPath('//div[@class="history_page"]/div[@class="weui_cells"]'), 'ui_map': { '小程序名': XPath('//p[@class="history_text"]') } }, '小程序列表': {'type': ui_list(WebElement), 'locator': XPath('//ul[@class="search_list"]/div/li'), 'ui_map': {'小程序名': XPath('//h3[@class="search_item_title"]/em[@class="highlight"]') } } } def open_app(self, app_name): '''进入小程序 ''' # time.sleep(1) if len(self.control('推荐搜索列表')) > 0: for it in self.control('推荐搜索列表'): if it.control('小程序名').inner_text.upper() == app_name.upper(): it.click() break elif len(self.control('搜索历史列表')) > 0: for it in self.control('搜索历史列表'): if it.control('小程序名').inner_text.upper() == app_name.upper(): it.click() break timeout = 5 time0 = time.time() while time.time() - time0 < timeout: if len(self.control('小程序列表')) > 0: break time.sleep(0.2) else: raise RuntimeError('未搜索到小程序') for it in self.control('小程序列表'): if it.control('小程序名').inner_text.upper() == app_name.upper(): it.click() return else: raise RuntimeError('小程序:%s 不存在' % app_name) for it in self.control('使用过的小程序列表'): if it.control('小程序名').inner_text.upper() == app_name.upper(): it.click() return else: raise RuntimeError('搜索结果中未找到小程序:%s' % app_name)
class Course_Detail_Element(): ''' 课程详情页页面元素封装 ''' ui_map = { 'url_404': { 'type': WebElement, 'locator': XPath('//link[@href="https://ke.qq.com/404.html"]') }, 'url_502': { 'type': WebElement, 'locator': XPath('//div[@class="error-code" and @jscontent="errorCode"]') }, 'url_403': { 'type': WebElement, 'locator': XPath('//body[@bgcolor="white"]') }, 'body': { 'type': WebElement, 'locator': XPath('//body') }, 'loginframe': { 'type': FrameElement, 'locator': XPath('//iframe[@name="login_frame_qq"]'), 'ui_map': { '帐号密码登录': XPath('//a[@id="switcher_plogin"]'), '帐号': { 'type': InputElement, 'locator': XPath('//input[@class="inputstyle" and @type="text"]') }, '清空账号': XPath('//a[@id="uin_del"]'), '密码': { 'type': InputElement, 'locator': XPath( '//input[@class="inputstyle password" and @type="password"]' ) }, '登录qq': XPath('//input[@id="login_button" and @value="登 录"]'), } }, 'course_task': { 'type': WebElement, 'locator': XPath('//div[@class="before-btn play-btn"]') }, 'task': { 'type': WebElement, 'locator': XPath('//li[@data-taid="3380594528670565"]') }, 'agency_logo': { 'type': WebElement, 'locator': XPath( '//img[@src="//p.qpic.cn/qqcourse/QFzQYCgCrxkME0JpnXdyHvL8Qp5ibroNYxoKLRGARbAiaB5PCBSeHPdnDQ6uibpdAg5/"]' ) }, 'agency_name': { 'type': WebElement, 'locator': XPath('//a[@class="tt-link js-agency-name"]') }, 'teacher_logo': { 'type': WebElement, 'locator': XPath( '//img[@src="//10.url.cn/eth/ajNVdqHZLLB30NjBSlDo1SeeLd1bPnDPr3BMBJ1KfTe56iaFCz6QzRCyDqZ8tyfQ6sWZwTicMBvO8/"]' ) }, 'teacher_name': { 'type': WebElement, 'locator': XPath( '//a[@class="tt-link js-teacher-name" and @title="咕泡教育-Mic"]') }, 'aside_course_image': { 'type': WebElement, 'locator': XPath('//img[@alt="课程封面"]') }, 'aside_course_link': { 'type': WebElement, 'locator': XPath('//a[@class="aside-course-link"]') }, 'course_card_list': { 'type': WebElement, 'locator': XPath('//li[@data-report-position="1"]') }, } ''' 控件的具体方法封装实现 ''' # 点击logo def click_header_index_logo(self): self.control('header-index-logo').click() # 点击该标签 time.sleep(1) # 等待1s self.find_url_404() # 判断跳转链接是否404 # self.exec_script('window.history.back()') self.exec_script( 'location.href = "https://ke.qq.com/course/185189"') # 跳转回来原来的地址 # 点击分类 def click_fenlei_list(self): self.control('分类').click() time.sleep(2) self.find_url_404() self.exec_script('location.href = "https://ke.qq.com/course/185189"') # self.exec_script('location.href = "https://ke.qq.com/404.html"') # 选择课程 def select_search_course(self): self.control('select-course').click() # 选择机构 def select_search_agency(self): self.control('select-agency').click() # 点击搜索课程、机构 def click_search(self): self.control('search-course').click() time.sleep(1) self.find_url_404() self.exec_script('location.href = "https://ke.qq.com/course/185189"') # 输入搜索词 def search_keyword(self, keyword): self.control('search-keyword').value = keyword # 点击下载 def click_download(self): self.control('download').click() # 点击登录 def click_login(self): self.control('login').click() # 点击QQ登录 def click_qq_login(self): self.control('qq_login').click() # 点击QQ登录(方法二) def click_qq_login_other(self): self.control('qq_login_other').click() # 点击切换QQ登录 def click_qq_login_text(self, account, password): self.control('loginframe.帐号密码登录').click() self.control('loginframe.帐号').value = account self.control('loginframe.密码').value = password self.control('loginframe.登录qq').click() # 点击切换QQ登录 # def click_qq_login_account(self, account): # # self.control('qq_login_text').click() # self.control('loginframe.帐号').value=account # 点击切换QQ登录 # def click_qq_login_password(self, password): # # self.control('qq_login_text').click() # self.control('loginframe.帐号').value=password # time.sleep(1) # self.control('loginframe.登录qq').click() # 点击课程封面播放按钮 def click_course_task(self): self.control('course_task').click() # 点击课程封面播放按钮 def click_task(self): self.control('task').click() # 点击机构logo def click_agency_logo(self): self.control('agency_logo').click() time.sleep(1) self.find_url_404() # test = self.url # print test # print self.browser_type # print self.title # print self.cookie # print self.ready_state # 点击机构name def click_agency_name(self): self.control('agency_name').click() time.sleep(1) self.find_url_404() # 点击老师logo def click_teacher_logo(self): self.control('teacher_logo').click() time.sleep(1) self.find_url_404() # 点击老师name def click_teacher_name(self): self.control('teacher_name').click() time.sleep(1) self.find_url_404() # 点击关联付费课程封面 def click_aside_course_image(self): self.control('aside_course_image').click() time.sleep(1) self.find_url_404() # 点击关联付费课程立即查看 def click_aside_course_link(self): self.control('aside_course_link').click() time.sleep(1) self.find_url_404() # 点击底部课程卡片 def click_course_card_list(self): self.control('course_card_list').click() time.sleep(1) self.find_url_404() ''' 浏览器通用方法实现: ''' # 获取页面url def get_page_url(self): # self.activate() page_url = self.url return page_url # 执行js回退 def run_exec_script(self): # self.exec_script('window.onerror = (e) => { console.error(e) };throw Error(123123)') self.exec_script('location.href = "https://ke.qq.com/404.html"') print('test') # 断言是否为404、502、403页面,捕获js error def find_url_404(self, driver): # if self.exec_script('location.href === "https://ke.qq.com/404.html"') == 'true': # 判断是否存在元素 if driver.current_url == "https://ke.qq.com/404.html": # 判断是否存在元素 raise RuntimeError('This is 404 page!!!') else: print("no 404 page, it's ok") # if self.control('url_502').exist == 'true': # 判断是否存在元素 try: driver.find_element_by_xpath( '//div[@class="error-code" and @jscontent="errorCode"]' ) # 判断是否存在元素 print('This is 502 page!!!') except: print("no 502 page, it's ok") # raise RuntimeError('This is 502 page!!!') # if self.control('url_403').exist == 'true': # 判断是否存在元素 # raise RuntimeError('This is 403 page!!!') # else: # print ("no 403 page, it's ok") try: driver.find_element_by_xpath( '//body[@bgcolor="white"]') # 判断是否存在元素 print('This is 403 page!!!') except: print("no 403 page, it's ok")