Python Selenium
最后修改于 2024 年 1 月 29 日
Python Selenium 教程演示了如何使用 Selenium 框架在 Python 中自动化 Web 应用程序测试。
Selenium
Selenium 是一个用于测试 Web 应用程序的可移植框架。Selenium 在 Windows、Linux 和 macOS 上运行。
Selenium WebDriver 是一组开源 API,用于自动化 Web 应用程序的测试。浏览器有专门的驱动程序,包括 Chrome、Firefox、Opera、Microsoft Edge。这些驱动程序需要下载并放置在 PATH 中。Selenium WebDriver 支持不同的编程语言,包括 Python、C# 和 Java。
Selenium 可以以全模式或无头模式运行。在无头模式下,浏览器不会启动。
Selenium 驱动程序
我们需要从 https://selenium-python.readthedocs.io/installation.html#drivers 下载我们使用的浏览器的驱动程序。驱动程序必须放置在 PATH 中,例如 /usr/bin/
、/usr/local/bin/
或当前工作目录。
Python Selenium 安装
使用以下命令安装 selenium 模块
$ pip install selenium
这将安装 selenium
模块。
Python Selenium Firefox 示例
对于 Firefox 浏览器,我们从 https://github.com/mozilla/geckodriver/releases 下载驱动程序(Windows 版为 geckodriver.exe
)。
#!/usr/bin/python from selenium.webdriver import Firefox from selenium.webdriver.firefox.options import Options opts = Options() opts.headless = True driver = Firefox(options=opts) try: driver.get('http://webcode.me') print(browser.title) assert 'My html page' == driver.title finally: driver.quit()
在示例中,我们使用 Firefox 的驱动程序测试网页标题。
opts = Options() opts.headless = True driver = Firefox(options=opts)
我们在无头模式下创建了一个驱动程序。浏览器不会启动。
try: driver.get('http://webcode.me') print(driver.title) assert 'My html page' == driver.title
我们向 webcode.me
页面发出 get 请求并获取其标题。我们对标题的内容进行断言。
finally: driver.quit()
最后,我们关闭驱动程序。
Python Selenium Chrome 示例
对于 Chrome 浏览器,我们从 sites.google.com/chromium.org/driver/ 下载驱动程序(Windows 版为 chromedriver.exe
)。
#!/usr/bin/python from selenium.webdriver import Chrome from selenium.webdriver.chrome.options import Options opts = Options() opts.headless = True driver = Chrome(options=opts, executable_path='chromedriver.exe') try: driver.get('http://webcode.me') assert 'My html page!' == driver.title finally: driver.quit()
在此示例中,我们使用 Chrome 浏览器。
driver = Chrome(options=opts, executable_path='chromedriver.exe')
我们创建了 Chrome 驱动程序的实例。executable_path
指向可执行文件;如果未指定,则假定可执行文件在 PATH 中。
assert 'My html page!' == driver.title
我们添加了一个额外的感叹号,以便测试失败。
> py chrome_get_title.py DevTools listening on ws://127.0.0.1:61178/devtools/browser/14d2fd68-eb2a-415a-9bf0-53a0f7b388d6 My html page Traceback (most recent call last): File "chrome_get_title.py", line 19, in <module> assert 'My html page!' == driver.title AssertionError
Python Selenium 页面源代码
page_source
属性获取当前页面的源代码。
#!/usr/bin/python from selenium.webdriver import Firefox from selenium.webdriver.firefox.options import Options opts = Options() opts.headless = True driver = Firefox(options=opts) try: driver.get('http://webcode.me') title = driver.title content = driver.page_source print(content) assert title == 'My html page' assert 'Today is a beautiful day' in content finally: driver.quit()
在示例中,我们测试了页面源代码中的标题和特定文本。
Python Selenium 查找元素
我们可以使用 find_elements_by_tag_name
、find_element_by_id
或 find_elements_by_class_name
等方法来定位 HTML 元素并获取其内容。
#!/usr/bin/python from selenium.webdriver import Firefox from selenium.webdriver.firefox.options import Options opts = Options() opts.headless = True driver = Firefox(options=opts) try: driver.get('http://webcode.me') els = driver.find_elements_by_tag_name("p") for el in els: print(el.text) finally: driver.close()
在示例中,我们获取并打印 webcode.me
主页上两个段落的文本。
els = driver.find_elements_by_tag_name("p")
我们使用 find_elements_by_tag_name
方法查找 p
标签。
for el in els: print(el.text)
我们遍历元素列表,并使用 text
属性打印其内容。
> py get_paragraphs.py Today is a beautiful day. We go swimming and fishing. Hello there. How are you?
Python Selenium 警告框
在接下来的示例中,我们展示了如何测试 JavaScript 警告框。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Test page</title> </head> <body> <button id="mybtn" onclick="alert('Hello there!')"> Click </button> </body> </html>
我们有一个带有按钮的 HTML 页面。当我们单击按钮时,会出现一个警告框。
#!/usr/bin/python import time from pathlib import Path from selenium.common.exceptions import TimeoutException from selenium.webdriver import Firefox from selenium.webdriver.support import expected_conditions as ec from selenium.webdriver.support.wait import WebDriverWait myfile = Path.cwd() / "index.html" driver = Firefox() try: driver.get(f'file://{myfile}') button = driver.find_element_by_id("mybtn") button.click() time.sleep(2) try: WebDriverWait(driver, 3).until(ec.alert_is_present(), 'Timed out waiting for confirmation popup to appear') alert = driver.switch_to.alert assert alert.text == 'Hello there!' alert.accept() print("alert accepted") except TimeoutException: print("no alert") time.sleep(5) finally: driver.quit()
在示例中,我们单击一个按钮元素并检查警告框的文本。
try: driver.get(f'file://{myfile}') button = driver.find_element_by_id("mybtn") button.click() time.sleep(2)
我们加载一个本地文件,找到按钮元素并单击它。在此示例中,浏览器会出现;因此,我们睡眠 2 秒,以便我们能看到发生了什么。
WebDriverWait(driver, 3).until(ec.alert_is_present(), 'Timed out waiting for confirmation popup to appear')
使用 WebDriverWait
,我们等待 3 秒钟以让警告出现。如果警告框未出现,我们会提供一条错误消息。
alert = driver.switch_to.alert assert alert.text == 'Hello there!'
我们检查警告框的文本。
Python Selenium unittest 示例
unittest
是一个 Python 单元测试框架。它是 JUnit 的 Python 版本,JUnit 是 Java 编程语言的原始单元测试框架。unittest
支持测试自动化、测试的设置和拆卸代码的共享、将测试聚合到集合中以及测试与报告框架的独立性。
unittest
提供了一个基类 TestCase
,可用于创建新的测试用例。setUp
是一个钩子方法,用于在执行测试夹具之前进行设置,而 tearDown
是一个钩子方法,用于在测试后对测试夹具进行拆卸。
一个 测试夹具 表示执行一个或多个测试所需的准备工作以及任何相关的清理操作。这可能涉及例如创建临时或代理数据库、目录或启动服务器进程。一个 测试用例 是引用单个测试的测试函数。函数名称必须以 test
开头。检查是通过各种断言方法执行的,例如 assertIn
、assertTrue
或 assertEqual
。
一个 测试套件 是测试用例、测试套件或两者的集合。它用于聚合应一起执行的测试。一个 测试运行器
是一个协调测试执行并将结果提供给用户的组件。运行器可以使用图形界面、文本界面或返回特殊值来指示测试执行的结果。unittest
、pytest
和 nose
是 Python 测试运行器的示例。
#!/usr/bin/python import unittest from selenium import webdriver from selenium.webdriver.firefox.options import Options class WebCode(unittest.TestCase): def setUp(self): opts = Options() opts.headless = True self.driver = webdriver.Firefox(options=opts) def test_title(self): self.driver.get("http://webcode.me") self.assertIn("My html page", self.driver.title) def test_paragraphs(self): self.driver.get("http://webcode.me") els = self.driver.find_elements_by_tag_name("p") self.assertIn('Today is a beautiful day', els[0].text) self.assertIn('Hello there', els[1].text) def tearDown(self): self.driver.close() if __name__ == "__main__": unittest.main()
我们有一个测试文件,其中我们检查 webcode.me
主页的标题和段落。
def setUp(self): opts = Options() opts.headless = True self.driver = webdriver.Firefox(options=opts)
在 setUp
方法中,我们设置了 Firefox 驱动程序。
def test_title(self): self.driver.get("http://webcode.me") self.assertIn("My html page", self.driver.title)
test_title
方法是一个单独的测试用例,它使用 assertIn
方法检查指定网页的标题。
def test_paragraphs(self): self.driver.get("http://webcode.me") els = self.driver.find_elements_by_tag_name("p") self.assertIn('Today is a beautiful day', els[0].text) self.assertIn('Hello there', els[1].text)
在 test_paragraphs
测试用例中,我们检查两个段落的内容。
def tearDown(self): self.driver.close()
在 tearDown
方法中,我们关闭驱动程序。
if __name__ == "__main__": unittest.main()
通过 main
方法,我们执行测试。
> py unittest_example.py .. ---------------------------------------------------------------------- Ran 2 tests in 13.273s OK
我们运行测试。unittest
对成功执行的测试用例显示一个点,对失败的测试用例显示 F,对测试执行期间发生的错误显示 E。
Python Selenium 与 pytest
pytest
模块是一个用于测试 Python 应用程序的 Python 库。它是 nose 和 unittest 的替代品。
$ pip install pytest
我们安装 pytest
库。
pytest
在目录中查找 test_*.py
或 *_test.py
文件。在选定的文件中,pytest
在类外部查找以 test 开头的测试函数,在以 Test 开头的测试类(不带 __init__
方法)中查找以 test 开头的测试方法。
#!/usr/bin/python import pytest from selenium.webdriver import Firefox from selenium.webdriver.firefox.options import Options @pytest.fixture def browser(): opts = Options() opts.headless = True driver = Firefox(options=opts) driver.implicitly_wait(5) yield driver # For cleanup, quit the driver driver.quit() def test_get_title(browser): browser.get("http://webcode.me") assert 'My html page' == browser.title
该示例展示了一个使用 pytest
模块的简单测试用例。
@pytest.fixture def browser(): opts = Options() opts.headless = True driver = Firefox(options=opts) ...
我们定义了一个 fixture。它设置了 Firefox 驱动程序。
driver.implicitly_wait(5)
我们在尝试交互之前隐式等待元素就绪。
yield driver
使用 yield
关键字,我们在 setup 结束时返回 driver 对象。
def test_get_title(browser): browser.get("http://webcode.me") assert 'My html page' == browser.title
我们有一个测试方法,用于检查网页的标题。它将浏览器 fixture 作为参数接收。
> pytest ============================== test session starts ============================== platform win32 -- Python 3.8.1, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 rootdir: C:\Users\Jano\Documents\python\SeleniumPytest collected 1 item tests\test_web.py . [100%] =============================== 1 passed in 6.31s ===============================
我们运行测试。
Python Selenium Flask 示例
在下一个示例中,我们将使用 pytest
和 Selenium 为 Flask Web 应用程序创建一个测试用例。我们测试 HTML 表单的响应。
app.py ├───static │ greet.html ├───templates │ index.html └───tests web_test.py
这是项目结构。
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Greet form</title> </head> <body> <p>Enter your name:</p> <form id="myform" action="greet"> <input name="name" type="text"> <button type="submit">Submit</button> </form> </body> </html>
我们在静态资源中有一个 greet 表单。该表单将文本值发送到 Flask 应用程序。
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>Greeting</title> </head> <body> <p> Hello {{ name }} </p> </body> </html>
这是 Flask 模板文件,它将消息返回给客户端。
#!/usr/bin/python from flask import Flask, render_template, request app = Flask(__name__) @app.route("/") def home(): return app.send_static_file('greet.html') @app.route("/greet") def greet(): username = request.args.get('name') return render_template('index.html', name=username) if __name__ == "__main__": app.run()
Flask 应用程序有两个路由:一个用于主页,一个用于问候。
#!/usr/bin/python import pytest from selenium.webdriver import Firefox from selenium.webdriver.firefox.options import Options from selenium.webdriver.support import expected_conditions as ec from selenium.webdriver.support.wait import WebDriverWait @pytest.fixture def browser(): opts = Options() opts.headless = True driver = Firefox(options=opts) driver.implicitly_wait(10) yield driver # For cleanup, quit the driver driver.quit() def test_greet_form(browser): user_name = "John" browser.get('https://:5000/') form = browser.find_element_by_id("myform") name = browser.find_element_by_name("name") name.send_keys(user_name) form.submit() WebDriverWait(browser, 12).until(ec.url_matches('/greet'), 'Timed out waiting for response') content = browser.page_source print(content) assert 'Hello John' in content
web_test.py
包含一个 greet 表单的测试用例。
def test_greet_form(browser): user_name = "John" browser.get('https://:5000/') ...
首先,我们获取 greet 表单。
form = browser.find_element_by_id("myform") name = browser.find_element_by_name("name") name.send_keys(user_name) form.submit()
我们检索表单的元素。我们将测试用户名添加到 input 标签并提交表单。
WebDriverWait(browser, 12).until(ec.url_matches('/greet'), 'Timed out waiting for response')
我们等待 Flask 重定向到 /greet
路由。
content = browser.page_source print(content) assert 'Hello John' in content
我们获取响应并检查响应中的消息。
> set FLASK_APP=app.py > flask run
我们运行 Flask 应用程序。
> pytest ========================== test session starts =========================== platform win32 -- Python 3.8.1, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 rootdir: C:\Users\Jano\PycharmProjects\SeleniumPytestFlask collected 1 item tests\web_test.py . [100%] =========================== 1 passed in 12.44s ===========================
从另一个 shell,我们执行 pytest
。
来源
在本文中,我们使用了 Python Selenium 框架。
作者
列出所有 Python 教程。