helium源码分析

2022-06-15 00:00:00 函数 代码 驱动 浏览器 退出

简介
前段时间在做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!');")


获取selenium的driver
get_driver()
1
跳转
go_to(url)
1
写入
write(text, into=None)
1
点击
click(element)
1
具体的api可以参考文档来学习。在这里不再赘述。这个库惊人的是代码量非常精简,只有几个文件:


代码分析
那下面我们一点点地来看一下这个库是如何对selenium进行封装的:

util包是工具包,包含了系统判断,数据结构转换的工具等。python方法比较多,咋一看感觉c语言的痕迹还是挺重的。
webdrivers: 放了几款webdriver驱动,但是不见得能适配,或须根据自己的浏览器版本更新驱动。
match_type.py :
selenium_wrappers.py (核心)
_impl/init.py : 实现api的核心
init.py : 一般的库这个文件是做类或者方法导入,或者显示版本号。如:


不过在helium包和_impl下都有方法实现,并没有把这部分代码放到单独的py文件中。


如图所示,这个文件就包含了几乎所有的helium的api。当然具体的实现还是要移步APIImpl
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
1
2

python atexit 模块定义了一个 register 函数,用于在 python 解释器中注册一个退出函数,这个函数在解释器正常终止时自动执行,一般用来做一些资源清理的操作。Note:如果程序是非正常crash,比如异常抛出或者通过os._exit()退出,注册的退出函数将不会被调用。
因此,我们在用ide,restart脚本的时候浏览器会自动退出。
然后,启动浏览器(利用selenium)
其他的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执行链
————————————————
版权声明:本文为CSDN博主「夜里慢慢行456」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u013257767/article/details/115625534

相关文章