前段时间在做web自动化测试方面的资料收集,无意间见到了一个selenium的封装库,使用下来真是要吹一波
官网:selenium-python-helium
文档:https://selenium-python-helium.readthedocs.io/en/latest/api.html
# A Helium function:
driver = start_chrome()
# A Selenium API:
driver.execute_script("alert('Hi!');")
get_driver()
go_to(url)
write(text, into=None)
click(element)
具体的api可以参考文档来学习。在这里不再赘述。这个库最惊人的是代码量非常精简,只有几个文件:
那下面我们一点点地来看一下这个库是如何对selenium进行封装的:
def kill_browser():
"""
Closes the current browser with all associated windows and potentially open
dialogs. Dialogs opened as a response to the browser closing (eg. "Are you
sure you want to leave this page?") are also ignored and closed.
This function is most commonly used to close the browser at the end of an
automation run::
start_chrome()
...
# Close Chrome:
kill_browser()
"""
_get_api_impl().kill_browser_impl()
def highlight(element):
"""
:param element: The element to highlight.
Highlights the given element on the webpage by drawing a red rectangle
around it. This is useful for debugging purposes. For example::
highlight("Helium")
highlight(Button("Sign in"))
"""
_get_api_impl().highlight_impl(element)
def _get_api_impl():
global _API_IMPL
if _API_IMPL is None:
_API_IMPL = APIImpl() # 具体的实现类
return _API_IMPL
我们以chrome的驱动为例看一下这几个主要的api干了些什么:
def _start_chrome_driver(self, headless, options):
chrome_options = self._get_chrome_options(headless, options)
try: # 有驱动获得driver
result = Chrome(options=chrome_options)
except WebDriverException:
# This usually happens when chromedriver is not on the PATH.
# 没有搜索到驱动,使用内嵌的driver 无论是否发生异常,都将返回一个driver
driver_path = self._use_included_web_driver('chromedriver')
result = Chrome(options=chrome_options, executable_path=driver_path)
atexit.register(self._kill_service, result.service)
return result
其他的api利用了python的包装器模式
在这里主要以write为例看看代码是如何设计的:
语法
write("Hello World!")
write("user12345", into="Username:")
write("Michael", into=Alert("Please enter your name"))
def might_spawn_window(f): # 或再建一个窗口
def f_decorated(self, *args, **kwargs):
driver = self.require_driver()
if driver.is_ie() and AlertImpl(driver).exists():
# Accessing .window_handles in IE when an alert is present raises an
# UnexpectedAlertPresentException. When DesiredCapability
# 'unexpectedAlertBehaviour' is not 'ignore' (the default is
# 'dismiss'), this leads to the alert being closed. Since we don't
# want to unintentionally close alert dialogs, we therefore do not
# access .window_handles in IE when an alert is present.
return f(self, *args, **kwargs)
window_handles_before = driver.window_handles[:]
result = f(self, *args, **kwargs)
# As above, don't access .window_handles in IE if an alert is present:
if not (driver.is_ie() and AlertImpl(driver).exists()):
if driver.is_firefox():
# Unlike Chrome, Firefox does not wait for new windows to open.
# Give it a little time to do so:
sleep(.2)
new_window_handles = [
h for h in driver.window_handles
if h not in window_handles_before
]
if new_window_handles:
driver.switch_to.window(new_window_handles[0])
return result
return f_decorated
使用过api,比如click的时候,就会发现这个接口极为简单
def _click(self, selenium_elt, offset):
self._move_to_element(selenium_elt, offset).click().perform()
def _move_to_element(self, element, offset):
result = self.require_driver().action()
if offset is not None:
result.move_to_element_with_offset(element, *offset)
else:
result.move_to_element(element)
return result
class WebDriverWrapper(Wrapper):
def __init__(self, target):
super(WebDriverWrapper, self).__init__(target)
self.last_manipulated_element = None
def action(self):
return ActionChains(self.target)
核心----move-to-element ----调用底层的ActionChain执行链