使用Selenium自动化操作浏览器!

Selenium可以自动化操作浏览器,例如:选择元素,输入,点击等,可以用于软件自动化测试,爬虫等工作,也可以做你想做的任何事情。

本文环境: Python3.12,Windows10,Selenium 4.15.2,Chrome 119.0.6045.160 

原理

WebDriver是一套标准API协议,由Selenium提出,W3C将其作为推荐标准,用于描述对UI界面的操作指令,使得客户端使用同样的函数就能操作不同的浏览器。自动化框架Appium也是基于WebDriver协议传输指令。

图片

Selenium各种编程语言的lib库(客户端)使用WebDriver协议,向Driver程序传输控制指令,各种浏览器都有自己对应的Driver程序,Driver程序实际上就是把WebDriver 指令翻译成实际的浏览器控制命令。

安装

一、安装Chrome

方法1.安装标准版Chrome(如果系统中已安装可跳过)

官网下载安装标准版(https://www.google.com/chrome/),Selenium会自动在PATH路径寻找系统安装的浏览器,并自动下载对应的Driver程序。

方法2.安装测试专用版

去chromiun官网(https://chromedriver.chromium.org/downloads) 下载各平台对应的测试专用版本Chrome和对应驱动,解压后放到项目路径。此种方式需要初始化驱动时配置浏览器和驱动的路径,后文会有介绍。

二、安装Python

去官网下载安装即可 https://www.python.org/downloads/windows/

可以自定义安装位置和特性。

图片

注:安装给所有人,默认安装到系统路径(C:\Program Files\)下,有些库文件会分散安装到系统其他路径。

安装给当前用户,默认安装到路径(C:\Users\username\AppData\Local\Programs\)下。所有文件都会安装到一个文件夹下,把这个目录复制到别处,只需自己配好PATH路径就能继续使用。

注:由于Python3.12的基础库有些变动,如果你使用Pycharm请升级其到最新版,否则可能管理不了虚拟环境。

三、安装selenium库

pip install selenium

示例:访问百度

import timefrom selenium import webdriverfrom selenium.webdriver.common.by import By
driver = webdriver.Chrome()driver.get("https://www.baidu.com/")print(driver.title)
input = driver.find_element(by=By.ID, value="kw")input.send_keys('abc')
submit = driver.find_element(by=By.XPATH, value='//*[@id="su"]')submit.click()
time.sleep(300)

第一次运行可能要等一段挺长的时间,之后会自动打开页面输入内容,点击搜索:

图片

初始化driver

以下初始化参数请按需选择

from selenium import webdriver
options = webdriver.ChromeOptions()
options.page_load_strategy = 'normal'  # 网页加载模式:等待所有资源都被下载options.binary_location = r".\chrome-win64\chrome.exe"  # 指定被操作的浏览器程序路径
# headless模式需要的三个配置,不需要可以注释掉options.add_argument("--headless")  # 无界面模式options.add_argument("--disable-gpu")  # headless模式下,windows系统可能需要options.add_argument('--window-size=1920,1080')  # 缺少此配置,headless模式可能点击不到元素
options.add_argument("--start-maximized")  # 启动时最大化窗口options.add_argument(f"--force-device-scale-factor={1}")  # 缩放后的高分屏截屏模糊,需要恢复options.add_argument("--test-type=gpu")  # 关掉提示:“Chrome测试版 仅适用于自动测试”
options.add_experimental_option("detach", True)  # driver退出,但保留浏览器(注意不要执行driver.quit())
switches = ['enable-automation',  # 关掉提示:“Chrome正受到自动测试软件的控制”            'enable-logging',  # 关闭浏览器日志            ]            options.add_experimental_option('excludeSwitches', switches)
prefs = {"credentials_enable_service": False,  # 禁止保存密码弹窗         "profile.password_manager_enabled": False,  # 禁止保存密码弹窗         }options.add_experimental_option("prefs", prefs)
service = webdriver.ChromeService(service_args=["--verbose", "--log-path=.\\qc1.log"], # chromedriver的日志                                 executable_path=r".\chromedriver-win64\chromedriver.exe" # chromedriver程序路径                                 )driver = webdriver.Chrome(options=options, service=service)
driver.implicitly_wait(50)  # 查找元素标签时,等待时长

注:浏览器启动后,可以在地址栏访问:chrome://version/ 查看启动参数,需要屏蔽的默认参数可以放到excludeSwitches中。

注:如果想用detach True参数,在Pycharm中不要直接Run,要在Terminal标签,或系统cmd命令行运行。或者excludeSwitches中包含'enable-logging'确保浏览器不输出日志。

注:关于指定所用的浏览器和web驱动

在4.10.0版本后,selenium包含了一个Selenium Manager工具,会自动探测系统上安装的浏览器位置,自动下载对应的web驱动程序,这种情况下也可以删除上文中这两个配置:上文的百度示例就是没有这两个配置,第一次运行自动下载驱动消耗了一段时间。

# 指定浏览器options.binary_location = r".\chrome-win64\chrome.exe"# 指定web驱动service = webdriver.ChromeService(executable_path=r".\chromedriver-win64\chromedriver.exe")
现在我也找了很多测试的朋友,做了一个分享技术的交流群,共享了很多我们收集的技术文档和视频教程。
如果你不想再体验自学时找不到资源,没人解答问题,坚持几天便放弃的感受
可以加入我们一起交流。而且还有很多在自动化,性能,安全,测试开发等等方面有一定建树的技术大牛
分享他们的经验,还会分享很多直播讲座和技术沙龙
可以免费学习!划重点!开源的!!!
qq群号:691998057【暗号:csdn999】

打开网页

打开网页,selenium只有get方法,其他方法只能操作浏览器,由浏览器或js脚本发送。​​​​​​​

driver.get('https://www.w3schools.com/js/default.asp')# driver.refresh() 刷新页面,如果链接未变,重复get无用,可以刷新。

网页操作简单来说就分两步:1. 定位元素 2.执行操作。​​​​​​​

from selenium.webdriver.common.by import Byaccept_button = driver.find_element(by=By.XPATH,                    value='//*[@id="accept-choices"]')accept_button.click()

元素定位

主要通过find_element()函数进行,有两个参数,by参数选择定位方式;value参数输入定位方式对应的值。

其他定位方式:

By.XPATH:使用XPATH定位: '//*[@id="accept-choices"]'。

By.TAG_NAME:使用tag名定位:  即h1,div,a等。

By.ID: 使用ID属性:<div id="content"></div>

By.NAME: 使用name属性:<div name="content"></div>

By.CSS_SELECTOR:  css选择器:"#book"

By.CLASS_NAME:类名:<div class="content"></div>

By.LINK_TEXT:通过链接文字:<a href="continue.html">Continue</a>

By.PARTIAL_LINK_TEXT:部分链接文字:上例中只写Cont
 

定位元素不只针对窗口,也可以从已经定位的元素开始,driver.find_element() 返回的是一个 WebElement,它也有find_element()方法​​​​​​​

table = driver.find_element(by=By.ID, value="table")t_body = table.find_element(by=By.TAG_NAME, value="tbody")t_tr = t_body.find_elements(by=By.TAG_NAME, value='tr')

元素操作​​​​​​​

# 按钮链接等button.click()# 文本框username_box.send_keys(username)# select元素from selenium.webdriver.support.ui import Selectselect_elm = driver.find_element(by=By.TAG_NAME, value='select')selecter = Select(select_elm)selecter.select_by_value("2023-12")

切换iframe和窗口

有时候你会发现,怎么也定位不到元素,这也许是因为他们处于不同的iframe或窗口,必须先切换过去才能操作。

切换iframe​​​​​​​

<iframe id="buttonframe" name="myframe"  src="https://seleniumhq.github.io">   <button>Click here</button></iframe>------------------------------------# Store iframe web elementiframe = driver.find_element(By.CSS_SELECTOR, "#modal > iframe")
# switch to selected iframedriver.switch_to.frame(iframe)# Switch frame by iddriver.switch_to.frame('buttonframe')
# Now click on buttondriver.find_element(By.TAG_NAME, 'button').click()
# switch back to default contentdriver.switch_to.default_content()

切换窗口​​​​​​​

driver.current_window_handle # 当前窗口句柄driver.window_handles # 所有的窗口列表,可以从中取出handle
# Opens a new tab and switches to new tabdriver.switch_to.new_window('tab')# Opens a new window and switches to new windowdriver.switch_to.new_window('window')driver.switch_to.window(handle) # 切换到一个窗口,driver.close() # 关闭窗口

等待(Wait)

点击了按钮或执行了某个操作后,浏览器需要一定的时间加载资源或进行计算,js也会改变DOM内容。

因此,很多时候我们需要等待一定的条件才能继续操作。

手工等待

最简单的等待可以添加time.sleep()硬性等待,短时间的等待(一两秒)是可以使用的,对于等待时长不固定,有较大概率等待时间较长的情况一般不要使用,但在遇到问题时可以临时用这种方法定位问题。

隐式等待

在初始化好driver后,使用如下语句配置

driver.implicitly_wait(20)

如果没有配置默认值为0,即如果元素没有就位会立刻返回错误;如果配置了则等待对用时长后元素还没有就位才返回错误;如果元素就位会立即返回,不会浪费时间。

显式等待(最重要)

显式等待,是等待某个或某些条件的成立,条件是否成立由一个函数判断,这个函数作为参数传寄给Wait机制的until()或until_not()函数:​​​​​​​

from selenium.webdriver.support.ui import WebDriverWait
wait = WebDriverWait(driver, timeout=20)element = wait.until(lambda d : revealed.is_displayed())wait.until_not(lambda d : revealed.is_displayed())
# 还可以配置其探测间隔,忽略的异常等errors = [NoSuchElementException, ElementNotInteractableException]wait = WebDriverWait(driver, timeout=2, poll_frequency=.2, ignored_exceptions=errors)wait.until(lambda d : revealed.send_keys("Displayed") or True)

until()函数直到回调函数返回"真"值,否则抛出超时异常;until_not()函数相反,直到回调函数返回"假"值就返回否则抛出异常,另外如果遇到被忽略的异常,会返回True。

回调函数接收一个参数,即初始化wait时的driver。​​​​​​​

def condition_fun(driver):    if time.time() > 2524579200: # 2050-01-01后满足条件        return Trueresp = wait.until(condition_fun)

系统预定义条件

系统预置了一些expected conditions函数,他们通过闭包的方式,生成一个符合until()函数需要的单参数函数:​​​​​​​

from selenium.webdriver.support import expected_conditions as ECf_condition = EC.element_to_be_clickable(submit_button)wait.until(f_condition) # f_condition是一个函数

EC.element_to_be_clickable()函数会帮我们生成需要的回调函数。这个函数等待指定的元素可点击。

函数的参数指定要等待的元素,有两种类型,一种是之前见过的使用find_element找到的元素,另一种是使用一个元组,传入定位方式和定位值,被称为locator:

例:​​​​​​​

# 传入元素submit_button = driver.find_element(by=By.XPATH, value='//*[@id="submit"]')submit_button = wait.until(EC.element_to_be_clickable(submit_button))if submit_button :    submit_button.click()
# 传入locatorsubmit_button = wait.until(EC.element_to_be_clickable(                     (By.XPATH, '//*[@id="submit"]')                  ))if submit_button :    submit_button.click()

预定义的条件很多,详情见官方文档,这里简单介绍几个:​​​​​​​

EC.alert_is_present() # 当前正弹出告警框,并返回告警框EC.element_attribute_to_include() # 元素包含某个属性EC.element_to_be_clickable() # 元素可被点击EC.visibility_of() # 元素可见EC.staleness_of() # 元素消失EC.text_to_be_present_in_element() # 元素种出现某个字符EC.title_contains(title) # 页面标题包含某字符串
# 还有些条件的组合函数EC.all_of() # 所有条件都满足EC.any_of() # 任何一个条件满足EC.none_of() # 所有条件都不满足

文档:https://www.selenium.dev/selenium/docs/api/py/webdriver_support/selenium.webdriver.support.expected_conditions.html

补充:等待AJAX请求结束,并获取其内容

由于前后端分离技术,越来越多的页面并不是后端渲染完再返回显示,而是先返回一个框架,通过AJAX请求异步获取数据,再用js渲染到页面。Selenium对js的这些请求没有处理。

网络波动会对下载产生很大影响,时不时会有一个很长的等待(概率低但不是没有),如果使用sleep()手动等待,就需要等待很长时间,才能保证每一次请求都能完成。

所以如果能准确地等待一个数据请求结束,将会节省很多时间。​​​​​​​

# 首先记得在初始化时打开performance日志options.set_capability(            "goog:loggingPrefs", {"performance": "ALL"}        )

这样就可以通过日志获得链接即将发送请求,响应以及响应结束三种状态。​​​​​​​

def ec_request_finish(url, timestamp):    """    等待ajax发起的GET或POST请求结束    :param url: 请求前缀,    :param timestamp: 请求开始前记录的时间,可帮助排除页面自动发起的请求,或减少处理的日志数量    :return: request_id, 可以通过它获取文件内容    """    request_id = ''
    def check_fish(driver):        for log in driver.get_log('performance'):            if timestamp * 1000 > log['timestamp'] or 'message' not in log:                continue
            log_entry = json.loads(log['message'])
            try:                method = log_entry['message']['method']                params = log_entry['message']['params']                if not request_id and method in ['Network.requestWillBeSent', 'Network.responseReceived']:                    if method == 'Network.requestWillBeSent' and \                            params['request']['method'] in ['POST', 'GET'] and \                            url in params['request']['url']:                        request_id = params['requestId']                    if method == 'Network.responseReceived' and \                            params['response']['method'] in ['POST', 'GET'] and \                            url in params['response']['url']:                        request_id = params['requestId']
                if request_id and method in ['Network.loadingFinished'] and \                        request_id == params['requestId']:                    return request_id            except Exception as e:                pass    return check_fish
# 等待请求结束request_id = wait.until(ec_request_finish('https://www.abc.com/x/y/z',0))# 获取返回的内容,此处以返回json格式字符串为例result = self.driver.execute_cdp_cmd("Network.getResponseBody", {"requestId": request_id})data = json.loads(result['body'])

浏览器操作

# 导航driver.back()driver.forward()driver.refresh()
# 获取信息driver.title # 标题driver.current_url # 当前链接driver.capabilities # 查看driver的一些配置
# Cookiesdriver.add_cookie({"name": "foo", "value": "bar"})driver.get_cookie("foo")driver.get_cookies() #获取所有域名的cookiesdriver.delete_cookie("foo")driver.delete_all_cookies()
# 执行js脚本,有些信息可以通过js获取,当然也可以做其他事情driver.execute_script('return arguments[0].innerText', header)
size = driver.get_window_size() # 获取窗口尺寸driver.set_window_size(1024, 768) # 设置窗口尺寸driver.get_window_position() # 获取窗口位置driver.set_window_position(0, 0) # 设置窗口位置driver.maximize_window() # 最大化driver.minimize_window() # 最小化driver.fullscreen_window() # 全屏显示,相当于F11

截屏​​​​​​​

# 对窗口截屏driver.get_screenshot_as_file('./image.png') # 截屏当前窗口,gng格式driver.save_screenshot('./image.png') # 对get_screenshot_as_file()的封装driver.get_screenshot_as_png() # 对窗口截屏,返回二进制png数据driver.get_screenshot_as_base64() # 对窗口截屏,返回base64数据
# 对目标元素截屏element = driver.find_element(...)element.screenshot('./image.png') element.screenshot_as_base64 # 注意不是函数,是property属性element.screenshot_as_png # 注意不是函数,是property属性

补充:截长屏的方法

一般的截屏工具截长屏是通过滚轮操作滚动条,然后不断拼接完成的。Selenium应该也可以这样操作,不断的滚动、切图、拼接。

这里分享一个更简单些的操作:设置窗口大小,使滚动条消失内容全部显示。但要注意,这种方式一般需要在headless模式下才能正常工作。

截屏浏览器:​​​​​​​

original_size = driver.get_window_size()height = driver.execute_script('return document.documentElement.scrollHeight')width = driver.execute_script('return document.documentElement.scrollWidth')
driver.set_window_size(width, height)  # the trick, and must in headless modescreenshot = form.screenshot_as_base64form.screenshot('image.png')driver.set_window_size(original_size['width'], original_size['height'])

截取带滚动条的元素:​​​​​​​

content = driver.find_element(by=By.XPATH, value='//div[@id="app-content"]')
original_size = driver.get_window_size()height = content.size['height']width = content.size['width']
driver.set_window_size(width, height+100)  # the trick, and must in headless mode# screenshot = content.screenshot_as_base64content.screenshot('image.png')driver.set_window_size(original_size['width'], original_size['height'])

下载文件

有些网页有文档或数据导出功能,点击按钮会下载文件,可以使用的相关参数有:

prefs = {         "download.default_directory": 'D:\\',  # 下载文件的保存地址,一定要是绝对地址         "download.prompt_for_download": False,         "download.directory_upgrade": True,          "profile.default_content_settings.popups": 0,         }options.add_experimental_option("prefs", prefs)

default_directory一定要注意写绝对地址,其他参数是屏蔽弹窗什么的,遇到了可以试试。

有时候想直接指定文件名,暂时看是不可以的,可以下载回来后再给文件改名。

警告框操作

警告框是通过js的 alert()、 confirm()、 prompt()函数弹出的​​​​​​​

# 使用wait等待警告框出现,并保存它alert = wait.until(EC.alert_is_present())# 或者直接获取警告框alert = driver.switch_to.alert
# 警告框的文字内容text = alert.text# 按确定按钮alert.accept()# 按取消按钮alert.dismiss()# 向prompt()输入内容,作为其返回值alert.send_keys("Selenium")

设备操作

能模拟键盘,鼠标,滚轮等操作。主要通过ActionChains,ActionBuilder 操作。

通用的一些操作​​​​​​​

.pause(3)  # 暂停3秒.perform() # 执行action chain

键盘操作​​​​​​​

from selenium.webdriver import Keys, ActionChains
# 直接输入到当前活跃元素,支持链式调用ActionChains(driver)\        .key_down(Keys.SHIFT)\        .send_keys("abc")\        .key_up(Keys.SHIFT)\        .send_keys("def")\        .perform()
# 发送到特定元素(会自动点击传入的元素)   text_input = driver.find_element(By.ID, "textInput")ActionChains(driver)\        .send_keys_to_element(text_input, "abc")\        .perform() 
# 剪切复制粘贴cmd_ctrl = Keys.COMMAND if sys.platform == 'darwin' else Keys.CONTROLActionChains(driver)\        .send_keys("Selenium!")\        .send_keys(Keys.ARROW_LEFT)\        .key_down(Keys.SHIFT)\        .send_keys(Keys.ARROW_UP)\        .key_up(Keys.SHIFT)\        .key_down(cmd_ctrl)\        .send_keys("xvv")\        .key_up(cmd_ctrl)\        .perform()

鼠标操作​​​​​​​

from selenium.webdriver import Keys, ActionChains
button= driver.find_element(By.ID, "button")ActionChains(driver)\        .move_to_element(button) \        .click() \        .perform()
# 移动鼠标.move_to_element(to_element).move_by_offset(xoffset, yoffset).move_to_element_with_offset(to_element, xoffset, yoffset)
# 点击相关.click() # 单击.double_click() # 双击.context_click() # 右击  .click_and_hold() # 单击不释放.release() # 释放按钮
# 拖动.drag_and_drop(source, target) # 一个元素拖动到另一个元素的位置.drag_and_drop_by_offset(source, xoffset, yoffset)  # 一个元素按像素拖动
# 滚轮滚动条,如果没效果尝试用一个新的ActionChains.scroll_by_amount(delta_x, delta_y).scroll_to_element(element).scroll_from_origin(origin, delta_x, delta_y)

补充:显示鼠标指针

鼠标指针是操作系统管理的,我们可以移动浏览器的指针焦点位置,但是操做系统不会让鼠标跟着动。所以我们要想直观些看到指针(debug用,正常时候不要用),需要自己画一个:​​​​​​​

    def enable_cursor(driver):        enable_cursor = """        (function() {          var seleniumFollowerImg = document.createElement("img");          seleniumFollowerImg.setAttribute('src', 'data:image/png;base64,'            + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAQAAACGG/bgAAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAA'            + 'HsYAAB7GAZEt8iwAAAAHdElNRQfgAwgMIwdxU/i7AAABZklEQVQ4y43TsU4UURSH8W+XmYwkS2I0'            + '9CRKpKGhsvIJjG9giQmliHFZlkUIGnEF7KTiCagpsYHWhoTQaiUUxLixYZb5KAAZZhbunu7O/PKf'            + 'e+fcA+/pqwb4DuximEqXhT4iI8dMpBWEsWsuGYdpZFttiLSSgTvhZ1W/SvfO1CvYdV1kPghV68a3'            + '0zzUWZH5pBqEui7dnqlFmLoq0gxC1XfGZdoLal2kea8ahLoqKXNAJQBT2yJzwUTVt0bS6ANqy1ga'            + 'VCEq/oVTtjji4hQVhhnlYBH4WIJV9vlkXLm+10R8oJb79Jl1j9UdazJRGpkrmNkSF9SOz2T71s7M'            + 'SIfD2lmmfjGSRz3hK8l4w1P+bah/HJLN0sys2JSMZQB+jKo6KSc8vLlLn5ikzF4268Wg2+pPOWW6'            + 'ONcpr3PrXy9VfS473M/D7H+TLmrqsXtOGctvxvMv2oVNP+Av0uHbzbxyJaywyUjx8TlnPY2YxqkD'            + 'dAAAAABJRU5ErkJggg==');          seleniumFollowerImg.setAttribute('id', 'selenium_mouse_follower');          seleniumFollowerImg.setAttribute('style', 'position: absolute; z-index: 99999999999; pointer-events: none; left:0; top:0');          document.body.appendChild(seleniumFollowerImg);
          document.onmousemove = function (e) {            document.getElementById("selenium_mouse_follower").style.left = e.pageX + 'px';            document.getElementById("selenium_mouse_follower").style.top = e.pageY + 'px';          };        })();
        // enableCursor();        """        driver.execute_script(enable_cursor)

鼠标除了常用的按键还有一些特殊的,比如“中键”。这些按键需要用更底层的action机制:ActionBuilder​​​​​​​

from selenium.webdriver.common.actions.action_builder import ActionBuilderfrom selenium.webdriver.common.actions.mouse_button import MouseButton       
# 按鼠标按键action = ActionBuilder(driver)action.pointer_action.pointer_down(MouseButton.MIDDLE)action.pointer_action.pointer_up(MouseButton.MIDDLE)action.perform()

注:ActionChains 底层也是使用ActionBuilder创建的action对象:​​​​​​​

class ActionChains:    def __init__(self, driver: WebDriver, duration: int = 250, devices: list[AnyDevice] | None = None) -> None:        ...        self.w3c_actions = ActionBuilder(driver, mouse=mouse, keyboard=keyboard, wheel=wheel, duration=duration)
    def click(self, on_element: WebElement | None = None) -> ActionChains:        if on_element:            self.move_to_element(on_element)
        self.w3c_actions.pointer_action.click()        self.w3c_actions.key_action.pause()        self.w3c_actions.key_action.pause()
        return self

因此,学习ActionBuilder可以通过学习ActionChains源码进行。

指点设备

触控屏,触摸板,指点笔之类的​​​​​​​

pointer_area = driver.find_element(By.ID, "pointerArea")pen_input = PointerInput(POINTER_PEN, "default pen")# 关键是替换默认的mouseaction = ActionBuilder(driver, mouse=pen_input)action.pointer_action\    .move_to(pointer_area)\    .pointer_down()\    .move_by(2, 2, tilt_x=-72, tilt_y=9, twist=86)\    .pointer_up(0)action.perform()

颜色支持

Selenium有个操作颜色的类,帮助判定颜色,配置颜色​​​​​​​

from selenium.webdriver.support.color import Color
# 创建颜色BLACK = Color.from_string('black')CHOCOLATE = Color.from_string('chocolate')HOTPINK = Color.from_string('hotpink')TRANSPARENT = Color.from_string('transparent')HEX_COLOUR = Color.from_string('#2F7ED8')RGB_COLOUR = Color.from_string('rgb(255, 255, 255)')RGB_COLOUR = Color.from_string('rgb(40%, 20%, 40%)')RGBA_COLOUR = Color.from_string('rgba(255, 255, 255, 0.5)')RGBA_COLOUR = Color.from_string('rgba(40%, 20%, 40%, 0.5)')HSL_COLOUR = Color.from_string('hsl(100, 0%, 50%)')HSLA_COLOUR = Color.from_string('hsla(100, 0%, 50%, 0.5)')
# 从页面元素获取颜色login_button = driver.find_element(By.ID,'login')login_button_colour = Color.from_string(login_button.value_of_css_property('color'))login_button_background_colour = Color.from_string(login_button.value_of_css_property('background-color'))
# 从颜色生成hex,rgb,rgba颜色login_button_background_colour.hex # '#ff69b4'login_button_background_colour.rgba # 'rgba(255, 105, 180, 1)'login_button_background_colour.rgb # 'rgb(255, 105, 180)'
# 判断元素的颜色assert login_button_background_colour == HOTPINK

总结:

本文描述了Selenium自动化操控浏览器的原理,环境安装,及其支持的各种操作,并补充了一些很有用的扩展功能,希望能帮助读者对Selenium有个整体的认识,更多操作请参考官方资料。

下面是配套资料,对于做【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!

最后: 可以在公众号:自动化测试老司机 ! 免费领取一份216页软件测试工程师面试宝典文档资料。以及相对应的视频学习教程免费分享!,其中包括了有基础知识、Linux必备、Shell、互联网程序原理、Mysql数据库、抓包工具专题、接口测试工具、测试进阶-Python编程、Web自动化测试、APP自动化测试、接口自动化测试、测试高级持续集成、测试架构开发测试框架、性能测试、安全测试等。

如果我的博客对你有帮助、如果你喜欢我的博客内容,请 “点赞” “评论” “收藏” 一键三连哦!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/10176.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python实现星号打印出金字塔

#编程实现下列图形的打印 a input() for i in range(int(a)//21): num * * ((i1)*2-1) print(num.center(int(a), )) 编译后通过。输入20后得到下面的星号金字塔

c#教程——索引器

前言&#xff1a; 索引器&#xff08;Indexer&#xff09;可以像操作数组一样来访问对象的元素。它允许你使用索引来访问对象中的元素&#xff0c;就像使用数组索引一样。在C#中&#xff0c;索引器的定义方式类似于属性&#xff0c;但具有类似数组的访问方式。 索引器&#x…

Cloudera的简介及安装部署

简介 Cloudera是一家位于美国的软件公司&#xff0c;成立于2008年&#xff0c;专注于为企业客户提供基于Apache Hadoop的软件、支持、服务以及培训。Cloudera的开源Apache Hadoop发行版&#xff0c;即Cloudera Distribution including Apache Hadoop&#xff08;CDH&am…

【计算机网络原理】初识网络原理和一些名词解释​​

˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好&#xff0c;我是xiaoxie.希望你看完之后,有不足之处请多多谅解&#xff0c;让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如…

未来办公新方式--智能体与程序完美配合

Agent AI智能体的未来 工作中&#xff0c;有时候我们就像是在不停地踩着缝纫机&#xff0c;重复地做着那些单调乏味的任务&#xff0c;不仅耗时费力&#xff0c;还特别容易出错。可是&#xff0c;咱们现在可是生活在数字化时代啊&#xff01;这时候&#xff0c;Python编程语言…

docker私有仓库registry

简介 Docker私有仓库的Registry是一个服务&#xff0c;主要用于存储、管理和分发Docker镜像。具体来说&#xff0c;Registry的功能包括&#xff1a; 存储镜像&#xff1a;Registry提供一个集中的地方来存储Docker镜像&#xff0c;包括镜像的层次结构和元数据。 版本控制&…

嵌入式人工智能是一个怎样的概念呢?

嵌入式人工智能将会是未来几年人工智能发展的主要方向之一&#xff0c;并且会伴随着一系列的职位和角色的出现。虽然目前还没有嵌入式人工智能的确切定义&#xff0c;但随着人工智能的不断发展&#xff0c;它势必会延伸到边缘、终端和嵌入式市场。 嵌入式人工智能具有速度快、功…

攻略:大学生三下乡投稿媒体网站和快速方法

作为当代大学生,不仅需要学习和掌握知识,更需要将所学知识运用到实践中,参与各种社会实践活动。其中,“三下乡”活动就是一个非常有意义的社会实践活动。三下乡社会实践活动新闻稿投稿网站有哪些?有哪些方式可以快速投稿呢&#xff1f;今天小编给大家一次讲个明白。 三下乡新…

高效文件管理:一键提取文件名关键字,快速创建对应文件夹

在数字化时代&#xff0c;文件管理成为我们日常工作中不可或缺的一部分。随着文件数量的不断增加&#xff0c;如何高效、有序地管理这些文件成为了许多人的挑战。传统的文件管理方法&#xff0c;如手动创建文件夹和分类文件&#xff0c;不仅耗时耗力&#xff0c;而且容易出错。…

KAN网络

目录 背景知识 什么是神经网络&#xff1f; 神经网络发展史 MP神经元模型 感知机模型 KAN 引言 MLP架构vsKAN架构 从数学定理方面来看&#xff1a; 从算法层面上看&#xff1a; 从实际应用过程看&#xff1a; KAN的架构细节 KAN的准确性 KAN的可解释性 监督学习…

https://是怎么实现的?

默认的网站建设好后都是http访问模式&#xff0c;这种模式对于纯内容类型的网站来说&#xff0c;没有什么问题&#xff0c;但如果受到中间网络劫持会让网站轻易的跳转钓鱼网站&#xff0c;为避免这种情况下发生&#xff0c;所以传统的网站改为https协议&#xff0c;这种协议自己…

MyBatis——在WEB中使用MyBatis(MVC架构模式)

一、在 Web 应用中使用 MyBatis 项目目录结构 pojo package org.qiu.bank.pojo;/*** 账户类&#xff0c;封装账户数据* author 秋玄* version 1.0* package org.qiu.bank.pojo* date 2022-09-27-20:31* since 1.0*/ public class Account {private Long id;private String …

Logit Standardization in Knowledge Distillation 知识蒸馏中的logit标准化

摘要 知识蒸馏涉及使用基于共享温度的softmax函数将软标签从教师转移到学生。然而&#xff0c;教师和学生之间共享温度的假设意味着他们的logits在logit范围和方差方面必须精确匹配。这种副作用限制了学生的表现&#xff0c;考虑到他们之间的能力差异&#xff0c;以及教师天生…

农业生产中,土壤墒情的监测方法有哪些?

农业是人类的生命之源&#xff0c;而土壤墒情则是农业生产的基础。我们应该倍加珍惜土地资源&#xff0c;合理利用水资源&#xff0c;努力创造出更加宜人的生长环境。让每一滴水都能为农作物带来生机&#xff0c;让每一寸土地都能孕育丰收。这样才能实现农业可持续发展的目标&a…

存内计算加速大模型——REM-CiM的RGB-事件融合多模态类比计算内存(CiM)技术

本文为大模型&存内计算融合专题的首篇文章&#xff0c;我们将以这篇名为《REM-CiM: Attentional RGB-Event Fusion Multi-modal Analog CiM for Area/Energy-efficient Edge Object Detection during both Day and Night》为例[1]&#xff0c;探讨其在文中提到的多模态大模…

护眼台灯和普通台灯差别很大吗?专业护眼灯品牌有哪些?

随着科技的不断演进&#xff0c;台灯的设计也日益脱胎换骨&#xff0c;从曾经的笨重造型转变为如今轻盈雅致的外观。它们的功能同样经历了多样化的革新&#xff0c;变得更加人性化和便捷。作为学习、阅读和办公环境中不可或缺的照明工具&#xff0c;台灯所提供的光线舒适度至关…

LazyDiffusion:革新交互式图像编辑的扩散模型

Adobe Research和特拉维夫大学的研究人员联合开发了一种名为LazyDiffusion的新型扩散变换器&#xff0c;它能够高效地生成部分图像更新&#xff0c;特别适用于交互式图像编辑。该模型通过创新的编码器-解码器架构&#xff0c;显著提升了图像编辑的效率&#xff0c;同时保持了与…

QML 本地存储(Setting,sqlite)

Qt hello - 专注于Qt的技术分享平台 QML 原生的储存方有两种&#xff1a; 1&#xff0c;Settings 跟QWidget 中的QSettings 一样&#xff0c;可以简单的存储一些配置。 2&#xff0c;Sqlite sqlite数据库。可以存储一些复杂的数据。 一&#xff0c;Settings 我们以一个按钮的位…

鸿蒙DevEco Studio 4.1 Release-模拟器启动方式错误

软件版本&#xff1a;DevEco Studio 4.1 Release 报错提示&#xff1a; 没有权限查看处理指导 Size on Disk 显示1.0MB 尝试方案&#xff08;统统无效&#xff09;&#xff1a; 1、“windows虚拟机监控程序平台”、"虚拟机平台"已开启 启用CPU虚拟化 2、C…

DIY可视化软件环境准备

DIY官网可视化工具做好的可视化拖拽开发工具无须编程、零代码基础、所见即所得设计工具支持轻松在线可视化导出微信小程序、支付宝小程序、头条小程序、H5、WebApp、UNIAPP等源码 支持组件库,高颜值,卡片,列表,轮播图,导航栏,按钮,标签,表单,单选,复选,下拉选择,多层选择,级联选…