使用Selenium含蓄等待获取页面元素(附带实际业务需求情景)

  Hello,大家好,又到了小猿分享技术的时间了。这回带来的是使用Selenium去网站上获取部分信息并且执行部分操作以及"含蓄"等待元素加载完成以及截取图片和网页刷新机制的技术点。

  解释说明:Selenium用于自动化测试,web自动化测试工具集,即使用该模块去模拟手动去网页上点击获取信息,是一个很好的自动化测试模块。

  关于selenium模块,其实它的主要目的是进行web自动化测试,获取信息是次要的,主要是为了测试web的性能,这里也只是针对关于在web页面上进行操作。

  该模块适用范围是当涉及去网页上进行一些页面切换以及页面元素加载不出来刷新页面重新获取以及截取网页截图等待元素加载出来等,注意,如果只是单纯地去爬取一些信息,还是建议使用requests或者urllib2或者使用scrapy,这些更专业,也更适合爬取信息,所以大家在选用技术工具的时候要明白需求,选择合适的技术,做正确的事情

这里介绍一下selenium,官网介绍如下:

What is Selenium?
Selenium automates browsers. That's it! What you do with that
power is entirely up to you. Primarily, it is for automating 
web applications for testing purposes, but is certainly not 
limited to just that. Boring web-based administration tasks 
can (and should!) be automated as well.
Selenium has the support of some of the largest browser 
vendors who have taken (or are taking) steps to make Selenium
a native part of their browser. It is also the core technology
in countless other browser automation tools, APIs and frameworks.

重点是这一句:it is for automating web applications for testing purposes, but is certainly not limited to just that,翻译过来就是:它是用于自动化Web应用程序的测试目的,但肯定不仅仅限于此功能。简单来说它是Web的自动化测试工具集。因此单独拿出来讲述,它也是够学一阵子的。

Selenium的优点我不用细说,可以进行自动化测试,节省人力,可以全天化测试Web,过程可视化,可以全程观察到测试流程等等,但是缺点也是不可忽略的。

缺点:

速度慢:这点很让人捉急,因为每次运行都会打开一个浏览器,如果没有设置还会加载图片,JS等一堆东西。

占用资源太多:打开浏览器本身就会占用很多资源。

对网络要求更高:因为加载了图片,JS等资源,会产生更多的流量。

爬取规模不能太大:没有公司使用它作为生产环境。

:因为它是一个工具集,自然使用起来要比一个单纯的requests模块来说要困难点。所以这篇文章也仅仅是针对我在工作中用到的部分技术点做一下分享。

首先是获取页面上的标签,不论是使用selenium还是其他的爬虫技术, 我们需要做的都离不开定位标签, 即获取网页上的某元素,而selenium是打开浏览器,加载元素,由于网络原因或者其他的因素,页面上的元素不一定能同时加载出来,这就会导致产生ElementNotVisibleException错误出现,这样会降低自动化测试脚本的稳定性,所以我们要使用设置元素等待来解决这种问题造成的不稳定。

一,元素含蓄等待

WebDriver设置了两种类型的等待: 含蓄等待明确等待,明确等待即作用于特定代码,使之在某条件下成立才执行,比如设置个time.sleep(),或者是设置一下别的条件,使之执行。而含蓄等待则是属于智能等待,是全局超时设置,它不是固定的等待时间,一旦定位到元素就继续往下执行。相较而言,含蓄等待更是我们想要的,因为这个更符合我们的需求。需要导入的是 WebDriverWait模块

from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
capabilities = {'chromeOptions': {'useAutomationExtension': False}}
driver = webdriver.Chrome(desired_capabilities=capabilities)
driver.maximize_window()
MAX_LOADING_TIME = 40
# 接下来我们要做的就是使用WebDriver语句去含蓄等待获取页面元素了。
# 语法是 WebDriverWait(driver, MAX_LOADING_TIME, 1).until(lambda x:x.find_element_by_xpath("//*[@id="main"]/div/div[2]/div[2]/div/div[2]/ul/li[3]"))

其作用是会在最大的加载时长内去获取该元素,一旦获取就往下执行,内部的lambda函数其实就是使用爬虫获取元素的方法,

方法如下:注意通过类名找元素需要注意有坑!!!

find_element_by_xpath
find_element_by_id
find_elements_by_class_name(注意使用该方法如果界面上不止一个该元素,
返回的是一个列表,如果想获取指定元素,需要使用索引进行取值) 例如
WebDriverWait(driver, MAX_LOADING_TIME, 1).until(
     lambda x: x.find_elements_by_class_name("addPoiToList"))[0]
需求场景

​ 之前的一个业务逻辑是登录某个网站,获取某页面部分信息,接着去另一个页面去发送相应信息给别的用户,因为这些个操作比较麻烦,涉及页面切换,必然需要网络加载,因为这一切都是连续进行的,关系较为密切,因此任何一块如果操作失败都会导致整个测试案例的失败,而这个又是个核心,所以这一块的功能很重要,之前的逻辑是使用显示等待,到处都是time.sleep() word 天!!!晕菜又很low 逼。

所以我做的处理是,将显示等待换成隐式等待(大换血!!!吐了3回),后来又将操作不同页面封装到不同的函数里面,进行单个函数调用,函数里面只是写常规操作,即获取到某标签,接着去做什么事情,try except 模式设计到外面写成一个装饰器,这个装饰器的作用是尝试执行封装的各个函数,当没有获取到某元素即出现异常时,会刷新网站页面, 接着再去尝试获取某元素,当再次失败时,再退出网页,此次测试结束,给的结果是执行某函数的功能失败。

二,装饰器

装饰器的结构如下:

import functools
def trigger_func_execute(be_executed_func):
    """
    Python decorator for execute the imported function with
    universal execution structure that is try to find 
    element in CCC if not find,refresh pages and search it
    again. if not find taking a screenshots and quit.
    :param be_executed_func:
    :return:
    """
    @functools.wraps(be_executed_func)
    def wrapper(current_normal_screenshot_path, 
                current_abnormal_screenshot_path, page_name):
        try:
            execution = be_executed_func(
                current_normal_screenshot_path,
                current_abnormal_screenshot_path)
            make_normal_selenium_screenshot(
                current_normal_screenshot_path,
                current_abnormal_screenshot_path, page_name)
            return execution
        except:
            try:
                driver.refresh()
                time.sleep(5)
                execution = be_executed_func(
                    current_normal_screenshot_path,
                    current_abnormal_screenshot_path)
                return execution
            except:
                make_abnormal_selenium_screenshot(
                    current_normal_screenshot_path,
                    current_abnormal_screenshot_path,
                    page_name)
                selenium_action['failed_step'] = 
                'Getting to %s Web page.' % wrapper.__name__
                return False

    return wrapper

其中使用了装饰器修复技术用来记录执行的函数名, 主要是用来记录下执行到哪一步函数出错了。

三,selenium截图

其中的

make_normal_selenium_screenshot 函数是用来在当执行某函数时正常情况下去截取一张图片,各个参数的意思是正常执行的图片存放路径,不正常存放路径,最后一个参数的意思是给截取的图片取的名字,使用的方法是,

driver.get_screenshot_as_file(file_path)

import time
def make_abnormal_selenium_screenshot(
    current_normal_screenshot_path, 
    current_abnormal_screenshot_path, 
    page_name):
    """
    Taking a screenshots of each page in CCC Backend.
    :param current_normal_screenshot_path
    :param page_name:each page name such as service_page
    :return:
    """
​
    screenshot_img_full_path = 
    current_abnormal_screenshot_path
    + '\\' + page_name + '_' + str(time.time()) + '.png'
    selenium_action['ccc_screenshot_img_full_path']
    = screenshot_img_full_path
    driver.get_screenshot_as_file(screenshot_img_full_path)

  这样整体实现的效果就是登录网站去进行操作,并在每一步关键的操作会截图,如果某元素不能捕获到,会刷新当前页面进行再次获取,如果再次获取不到,截取异常图片并且保留到异常的文件夹中,并且记录下来失败的那一项的函数名。

  关键点是划分清操作不同页面的范围,正确描述不同的操作步骤,这样在做我们的自动化测试过程中能让测试者很快理解步骤,对执行的结果也能很快定位出错误的位置,错误的原因以及其它必要的信息。

  总结就是使用了含蓄等待替代生硬的显示等待,使用装饰器避免代码的重复性,使用selenium截图保留事故现场。正常处理也进行截图方便后续分析。

结语,关于Selenium的相关部分的知识还有很多,我这里只不过只针对我做过的需求场景总结了一下相关的知识技术,学海无涯,希望我的分享能给你带来一点学习工作上的一点启发,喜欢的话就转发一下呗。知识分享也是一种高尚的行为。大家一起努力。向知识的高峰攀登不止!!!, 更多内容,可关注我的公众号获取, 你们的支持是我分享的最大动力。

 

猜你喜欢

转载自www.cnblogs.com/f-g-f/p/12150598.html