diff --git a/DrissionPage/config.py b/DrissionPage/config.py index 6412e3e..db23e58 100644 --- a/DrissionPage/config.py +++ b/DrissionPage/config.py @@ -128,6 +128,10 @@ class OptionsManager(object): return path + def save_to_default(self) -> str: + """保存当前配置到默认ini文件""" + return self.save('default') + class SessionOptions(object): def __init__(self, read_file: bool = True, ini_path: str = None): @@ -437,6 +441,10 @@ class SessionOptions(object): return path + def save_to_default(self) -> str: + """保存当前配置到默认ini文件""" + return self.save('default') + def as_dict(self) -> dict: """以字典形式返回本对象""" return _session_options_to_dict(self) @@ -522,6 +530,10 @@ class DriverOptions(Options): return path + def save_to_default(self) -> str: + """保存当前配置到默认ini文件""" + return self.save('default') + def remove_argument(self, value: str) -> 'DriverOptions': """移除一个argument项 \n :param value: 设置项名,有值的设置项传入设置名称即可 diff --git a/DrissionPage/configs.ini b/DrissionPage/configs.ini index 36a4f56..b373203 100644 --- a/DrissionPage/configs.ini +++ b/DrissionPage/configs.ini @@ -1,11 +1,11 @@ [paths] -chromedriver_path = D:\python\Chrome92\chromedriver.exe +chromedriver_path = tmp_path = [chrome_options] debugger_address = 127.0.0.1:9222 -binary_location = D:\python\Chrome92\chrome.exe -arguments = ['--no-sandbox', '--disable-gpu', '--ignore-certificate-errors', '--disable-infobars', '--user-data-dir=D:\\python\\Chrome62\\userData'] +binary_location = +arguments = ['--no-sandbox', '--disable-gpu', '--ignore-certificate-errors', '--disable-infobars'] extensions = [] experimental_options = {'prefs': {'profile.default_content_settings.popups': 0, 'profile.default_content_setting_values': {'notifications': 2}, 'plugins.plugins_list': [{'enabled': False, 'name': 'Chrome PDF Viewer'}]}, 'useAutomationExtension': False, 'excludeSwitches': ['enable-automation']} timeouts = {'implicit': 10.0, 'pageLoad': 30.0, 'script': 30.0} diff --git a/DrissionPage/driver_element.py b/DrissionPage/driver_element.py index a487f57..8f3ed9f 100644 --- a/DrissionPage/driver_element.py +++ b/DrissionPage/driver_element.py @@ -330,15 +330,13 @@ class DriverElement(DrissionElement): def wait_ele(self, loc_or_ele: Union[str, tuple, DrissionElement, WebElement], - mode: str, - timeout: float = None) -> bool: + timeout: float = None) -> 'ElementWaiter': """等待子元素从dom删除、显示、隐藏 \n :param loc_or_ele: 可以是元素、查询字符串、loc元组 - :param mode: 等待方式,可选:'del', 'display', 'hidden' :param timeout: 等待超时时间 :return: 等待是否成功 """ - return _wait_ele(self, loc_or_ele, mode, timeout) + return ElementWaiter(self, loc_or_ele, timeout) def style(self, style: str, pseudo_ele: str = '') -> str: """返回元素样式属性值,可获取伪元素属性值 \n @@ -494,19 +492,19 @@ class DriverElement(DrissionElement): from warnings import warn warn("此方法下个版本将停用,请用scroll属性代替。", DeprecationWarning, stacklevel=2) if mode == 'top': - self.scroll.top() + self.scroll.to_top() elif mode == 'bottom': - self.scroll.bottom() + self.scroll.to_bottom() elif mode == 'half': - self.scroll.half() + self.scroll.to_half() elif mode == 'rightmost': - self.scroll.rightmost() + self.scroll.to_rightmost() elif mode == 'leftmost': - self.scroll.leftmost() + self.scroll.to_leftmost() elif mode == 'up': self.scroll.up(pixel) @@ -1058,82 +1056,92 @@ class Select(object): i.click() -def _wait_ele(page_or_ele, - loc_or_ele: Union[str, tuple, DriverElement, WebElement], - mode: str, - timeout: float = None) -> bool: - """等待元素从dom删除、显示、隐藏 \n - :param page_or_ele: 要等待子元素的页面或元素 - :param loc_or_ele: 可以是元素、查询字符串、loc元组 - :param mode: 等待方式,可选:'del', 'display', 'hidden' - :param timeout: 等待超时时间 - :return: 等待是否成功 - """ - if mode.lower() not in ('del', 'display', 'hidden'): - raise ValueError('mode参数只能是"del"、"display"或"hidden"。') +class ElementWaiter(object): + """等待元素在dom中某种状态,如删除、显示、隐藏""" - if isinstance(page_or_ele, BaseElement): - page = page_or_ele.page - ele_or_driver = page_or_ele.inner_ele - else: - page = page_or_ele - ele_or_driver = page_or_ele.driver + def __init__(self, + page_or_ele, + loc_or_ele: Union[str, tuple, DriverElement, WebElement], + timeout: float = None): + """等待元素在dom中某种状态,如删除、显示、隐藏 \n + :param page_or_ele: 页面或父元素 + :param loc_or_ele: 要等待的元素,可以是已有元素、定位符 + :param timeout: 超时时间,默认读取页面超时时间 + """ + if isinstance(page_or_ele, DriverElement): + page = page_or_ele.page + self.driver = page_or_ele.inner_ele + else: + page = page_or_ele + self.driver = page_or_ele.driver - timeout = timeout or page.timeout - is_ele = False + if isinstance(loc_or_ele, DriverElement): + self.target = loc_or_ele.inner_ele - if isinstance(loc_or_ele, DriverElement): - loc_or_ele = loc_or_ele.inner_ele - is_ele = True + elif isinstance(loc_or_ele, WebElement): + self.target = loc_or_ele - elif isinstance(loc_or_ele, WebElement): - is_ele = True + elif isinstance(loc_or_ele, str): + self.target = str_to_loc(loc_or_ele) - elif isinstance(loc_or_ele, str): - loc_or_ele = str_to_loc(loc_or_ele) + elif isinstance(loc_or_ele, tuple): + self.target = loc_or_ele - elif isinstance(loc_or_ele, tuple): - pass + else: + raise TypeError('loc_or_ele参数只能是str、tuple、DriverElement 或 WebElement类型。') - else: - raise TypeError('loc_or_ele参数只能是str、tuple、DriverElement 或 WebElement类型') + self.timeout = timeout if timeout is not None else page.timeout - # 当传入参数是元素对象时 - if is_ele: - end_time = time() + timeout + def delete(self) -> bool: + """等待元素从dom删除""" + return self._wait_ele('del') - while time() < end_time: - if mode == 'del': - try: - loc_or_ele.is_enabled() - except Exception: + def display(self) -> bool: + """等待元素从dom显示""" + return self._wait_ele('display') + + def hidden(self) -> bool: + """等待元素从dom隐藏""" + return self._wait_ele('hidden') + + def _wait_ele(self, mode: str) -> bool: + """执行等待 + :param mode: 等待模式 + :return: 是否等待成功 + """ + if isinstance(self.target, WebElement): + end_time = time() + self.timeout + while time() < end_time: + if mode == 'del': + try: + self.target.is_enabled() + except Exception: + return True + + elif mode == 'display' and self.target.is_displayed(): return True - elif mode == 'display' and loc_or_ele.is_displayed(): - return True + elif mode == 'hidden' and not self.target.is_displayed(): + return True - elif mode == 'hidden' and not loc_or_ele.is_displayed(): - return True - - return False - - # 当传入参数是控制字符串或元组时 - else: - try: - if mode == 'del': - WebDriverWait(ele_or_driver, timeout).until_not(ec.presence_of_element_located(loc_or_ele)) - - elif mode == 'display': - WebDriverWait(ele_or_driver, timeout).until(ec.visibility_of_element_located(loc_or_ele)) - - elif mode == 'hidden': - WebDriverWait(ele_or_driver, timeout).until_not(ec.visibility_of_element_located(loc_or_ele)) - - return True - - except Exception: return False + else: + try: + if mode == 'del': + WebDriverWait(self.driver, self.timeout).until_not(ec.presence_of_element_located(self.target)) + + elif mode == 'display': + WebDriverWait(self.driver, self.timeout).until(ec.visibility_of_element_located(self.target)) + + elif mode == 'hidden': + WebDriverWait(self.driver, self.timeout).until_not(ec.visibility_of_element_located(self.target)) + + return True + + except Exception: + return False + class Scroll(object): """用于滚动的对象""" @@ -1149,26 +1157,34 @@ class Scroll(object): self.t1 = 'window' self.t2 = 'document.documentElement' - def top(self) -> None: + def to_top(self) -> None: """滚动到顶端,水平位置不变""" self.driver.run_script(f'{self.t1}.scrollTo({self.t2}.scrollLeft,0);') - def bottom(self) -> None: + def to_bottom(self) -> None: """滚动到底端,水平位置不变""" self.driver.run_script(f'{self.t1}.scrollTo({self.t2}.scrollLeft,{self.t2}.scrollHeight);') - def half(self) -> None: + def to_half(self) -> None: """滚动到垂直中间位置,水平位置不变""" self.driver.run_script(f'{self.t1}.scrollTo({self.t2}.scrollLeft,{self.t2}.scrollHeight/2);') - def rightmost(self) -> None: + def to_rightmost(self) -> None: """滚动到最右边,垂直位置不变""" self.driver.run_script(f'{self.t1}.scrollTo({self.t2}.scrollWidth,{self.t2}.scrollTop);') - def leftmost(self) -> None: + def to_leftmost(self) -> None: """滚动到最左边,垂直位置不变""" self.driver.run_script(f'{self.t1}.scrollTo(0,{self.t2}.scrollTop);') + def to_location(self, x: int, y: int) -> None: + """滚动到指定位置 \n + :param x: 水平距离 + :param y: 垂直距离 + :return: None + """ + self.driver.run_script(f'{self.t1}.scrollTo({x},{y});') + def up(self, pixel: int = 300) -> None: """向上滚动若干像素,水平位置不变 \n :param pixel: 滚动的像素 @@ -1185,7 +1201,7 @@ class Scroll(object): self.driver.run_script(f'{self.t1}.scrollBy(0,{pixel});') def left(self, pixel: int = 300) -> None: - """向左滚动若干像素,水平位置不变 \n + """向左滚动若干像素,垂直位置不变 \n :param pixel: 滚动的像素 :return: None """ @@ -1193,7 +1209,7 @@ class Scroll(object): self.driver.run_script(f'{self.t1}.scrollBy({pixel},0);') def right(self, pixel: int = 300) -> None: - """向右滚动若干像素,水平位置不变 \n + """向右滚动若干像素,垂直位置不变 \n :param pixel: 滚动的像素 :return: None """ diff --git a/DrissionPage/driver_page.py b/DrissionPage/driver_page.py index 327c426..7828d6b 100644 --- a/DrissionPage/driver_page.py +++ b/DrissionPage/driver_page.py @@ -18,7 +18,7 @@ from selenium.webdriver.support.wait import WebDriverWait from .base import BasePage from .common import get_usable_path -from .driver_element import DriverElement, make_driver_ele, _wait_ele, Scroll +from .driver_element import DriverElement, make_driver_ele, Scroll, ElementWaiter from .session_element import make_session_ele @@ -62,13 +62,6 @@ class DriverPage(BasePage): from json import loads return loads(self('t:pre').text) - @property - def scroll(self) -> Scroll: - """用于滚动滚动条的对象""" - if self._scroll is None: - self._scroll = Scroll(self) - return self._scroll - def get(self, url: str, go_anyway: bool = False, @@ -181,13 +174,6 @@ class DriverPage(BasePage): self._timeout = second self._wait_object = None - @property - def timeouts(self) -> dict: - """返回三种超时时间,selenium4以上版本可用""" - return {'implicit': self.timeout, - 'pageLoad': self.driver.timeouts.page_load, - 'script': self.driver.timeouts.script} - def _try_to_connect(self, to_url: str, times: int = 0, @@ -238,6 +224,13 @@ class DriverPage(BasePage): return self._wait_object + @property + def timeouts(self) -> dict: + """返回三种超时时间,selenium4以上版本可用""" + return {'implicit': self.timeout, + 'pageLoad': self.driver.timeouts.page_load, + 'script': self.driver.timeouts.script} + @property def tabs_count(self) -> int: """返回标签页数量""" @@ -266,6 +259,28 @@ class DriverPage(BasePage): """返回当前焦点所在元素""" return DriverElement(self.driver.switch_to.active_element, self) + @property + def scroll(self) -> Scroll: + """用于滚动滚动条的对象""" + if self._scroll is None: + self._scroll = Scroll(self) + return self._scroll + + @property + def to_frame(self) -> 'ToFrame': + """用于跳转到frame的对象,调用其方法实现跳转 \n + 示例: \n + page.to_frame.by_loc('tag:iframe') - 通过传入frame的查询字符串定位 \n + page.to_frame.by_loc((By.TAG_NAME, 'iframe')) - 通过传入定位符定位 \n + page.to_frame.by_id('iframe_id') - 通过frame的id属性定位 \n + page.to_frame('iframe_name') - 通过frame的name属性定位 \n + page.to_frame(iframe_element) - 通过传入元素对象定位 \n + page.to_frame(0) - 通过frame的序号定位 \n + page.to_frame.main() - 跳到最顶层 \n + page.to_frame.parent() - 跳到上一层 + """ + return ToFrame(self) + def set_timeouts(self, implicit: float = None, pageLoad: float = None, script: float = None) -> None: """设置超时时间,单位为秒,selenium4以上版本有效 \n :param implicit: 查找元素超时时间 @@ -284,15 +299,13 @@ class DriverPage(BasePage): def wait_ele(self, loc_or_ele: Union[str, tuple, DriverElement, WebElement], - mode: str, - timeout: float = None) -> bool: + timeout: float = None) -> 'ElementWaiter': """等待元素从dom删除、显示、隐藏 \n :param loc_or_ele: 可以是元素、查询字符串、loc元组 - :param mode: 等待方式,可选:'del', 'display', 'hidden' :param timeout: 等待超时时间 :return: 等待是否成功 """ - return _wait_ele(self, loc_or_ele, mode, timeout) + return ElementWaiter(self, loc_or_ele, timeout) def check_page(self) -> Union[bool, None]: """检查页面是否符合预期 \n @@ -372,55 +385,6 @@ class DriverPage(BasePage): tab = self.driver.window_handles[tab] if isinstance(tab, int) else tab self.driver.switch_to.window(tab) - def to_frame(self, loc_or_ele: Union[int, str, tuple, WebElement, DriverElement] = 'main') -> 'DriverPage': - """跳转到frame \n - 可接收frame序号(0开始)、id或name、查询字符串、loc元组、WebElement对象、DriverElement对象, \n - 传入 'main' 跳到最高层,传入 'parent' 跳到上一层 \n - 示例: \n - to_frame('tag:iframe') - 通过传入frame的查询字符串定位 \n - to_frame('iframe_id') - 通过frame的id属性定位 \n - to_frame('iframe_name') - 通过frame的name属性定位 \n - to_frame(iframe_element) - 通过传入元素对象定位 \n - to_frame(0) - 通过frame的序号定位 \n - to_frame('main') - 跳到最高层 \n - to_frame('parent') - 跳到上一层 \n - :param loc_or_ele: iframe的定位信息 - :return: 返回自己,用于链式操作 - """ - # 根据序号跳转 - if isinstance(loc_or_ele, int): - self.driver.switch_to.frame(loc_or_ele) - - elif isinstance(loc_or_ele, str): - # 跳转到最上级 - if loc_or_ele == 'main': - self.driver.switch_to.default_content() - - # 跳转到上一层 - elif loc_or_ele == 'parent': - self.driver.switch_to.parent_frame() - - # 传入id或name - elif ':' not in loc_or_ele and '=' not in loc_or_ele and not loc_or_ele.startswith(('#', '.')): - self.driver.switch_to.frame(loc_or_ele) - - # 传入控制字符串 - else: - ele = self.ele(loc_or_ele) - self.driver.switch_to.frame(ele.inner_ele) - - elif isinstance(loc_or_ele, WebElement): - self.driver.switch_to.frame(loc_or_ele) - - elif isinstance(loc_or_ele, DriverElement): - self.driver.switch_to.frame(loc_or_ele.inner_ele) - - elif isinstance(loc_or_ele, tuple): - ele = self.ele(loc_or_ele) - self.driver.switch_to.frame(ele.inner_ele) - - return self - def screenshot(self, path: str, filename: str = None) -> str: """截取页面可见范围截图 \n :param path: 保存路径 @@ -453,19 +417,19 @@ class DriverPage(BasePage): from warnings import warn warn("此方法下个版本将停用,请用scroll属性代替。", DeprecationWarning, stacklevel=2) if mode == 'top': - self.scroll.top() + self.scroll.to_top() elif mode == 'bottom': - self.scroll.bottom() + self.scroll.to_bottom() elif mode == 'half': - self.scroll.half() + self.scroll.to_half() elif mode == 'rightmost': - self.scroll.rightmost() + self.scroll.to_rightmost() elif mode == 'leftmost': - self.scroll.leftmost() + self.scroll.to_leftmost() elif mode == 'up': self.scroll.up(pixel) @@ -558,6 +522,91 @@ class DriverPage(BasePage): return text +class ToFrame(object): + """用于处理焦点跳转到页面框架的类""" + + def __init__(self, page: DriverPage): + self.page = page + + def __call__(self, condition: Union[int, str, tuple, WebElement, DriverElement] = 'main'): + """用于兼容旧版,以后的版本会删除""" + from warnings import warn + warn("建议用to_frame.main()等方式使用此功能。", DeprecationWarning, stacklevel=2) + + if condition == 'main': + self.main() + elif condition == 'parent': + self.parent() + elif isinstance(condition, (DriverElement, WebElement)): + self.by_ele(condition) + elif isinstance(condition, int): + self.by_index(condition) + elif ':' not in condition and '=' not in condition and not condition.startswith(('#', '.', '@')): + self.by_id(condition) + else: + self.by_loc(condition) + + return self.page + + def main(self) -> DriverPage: + """焦点跳转到最高层级框架""" + self.page.driver.switch_to.default_content() + return self.page + + def parent(self, level: int = 1) -> DriverPage: + """焦点跳转到上级框架,可指定上级层数 \n + :param level: 上面第几层框架 + :return: 框架所在页面对象 + """ + if level < 1: + raise ValueError('level参数须是大于0的整数。') + for _ in range(level): + self.page.driver.switch_to.parent_frame() + return self.page + + def by_id(self, id_: str) -> DriverPage: + """焦点跳转到id为该值的(i)frame \n + :param id_: (i)frame的id属性值 + :return: 框架所在页面对象 + """ + self.page.driver.switch_to.frame(id_) + return self.page + + def by_name(self, name: str) -> DriverPage: + """焦点跳转到name为该值的(i)frame \n + :param name: (i)frame的name属性值 + :return: 框架所在页面对象 + """ + self.page.driver.switch_to.frame(name) + return self.page + + def by_index(self, index: int) -> DriverPage: + """焦点跳转到页面中第几个(i)frame \n + :param index: 页面中第几个(i)frame + :return: 框架所在页面对象 + """ + self.page.driver.switch_to.frame(index) + return self.page + + def by_loc(self, loc: Union[str, tuple]) -> DriverPage: + """焦点跳转到根据定位符获取到的(i)frame \n + :param loc: 定位符,支持selenium原生和DriverPage定位符 + :return: 框架所在页面对象 + """ + self.page.driver.switch_to.frame(self.page(loc).inner_ele) + return self.page + + def by_ele(self, ele: Union[DriverElement, WebElement]) -> DriverPage: + """焦点跳转到传入的(i)frame元素对象 \n + :param ele: (i)frame元素对象 + :return: 框架所在页面对象 + """ + if isinstance(ele, DriverElement): + ele = ele.inner_ele + self.page.driver.switch_to.frame(ele) + return self.page + + def _get_handles(handles: list, num_or_handles: Union[int, str, list, tuple]) -> set: """返回指定标签页组成的set :param handles: handles列表 diff --git a/docs/使用方法/元素操作.md b/docs/使用方法/元素操作.md index d64e863..dda934d 100644 --- a/docs/使用方法/元素操作.md +++ b/docs/使用方法/元素操作.md @@ -30,6 +30,8 @@ ele.click(timeout = 10) # 不断重试点击,直到遮罩层消失,或到 ele.click(by_js=True) # 无视遮罩层,直接用 js 点击下方元素 ``` + + ## click_at() 此方法用于带偏移量点击元素,偏移量相对于元素左上角坐标。不传入 x 或 y 值时点击元素中点。可选择是否用 js 方式点击,但不会进行重试。 @@ -55,11 +57,13 @@ ele.click_at(x=50) ele.click_at() ``` + + ## r_click() 此方法实现右键单击元素。 -无参数。 +参数:无 返回:None @@ -67,6 +71,8 @@ ele.click_at() ele.r_click() ``` + + ## r_click_at() 此方法用于带偏移量右键点击元素,用法和 click_at() 相似,但没有 by_js 参数。 @@ -83,6 +89,8 @@ ele.r_click() ele.r_click_at(50, 50) ``` + + ## input() 此方法用于向元素输入文本或组合键,也可用于输入文件路径到 input 元素(文件间用 \n 间隔)。可选择输入前是否清空元素。 @@ -109,12 +117,27 @@ ele.input('Hello world!\n') # 输入组合键 from selenium.webdriver import Keys + ele.input((Keys.CONTROL, 'a'), insure=False) # 向上传文本控件输入文本路径(传入多个路径) ele.input('D:\\test1.txt\nD:\\test2.txt') ``` +## clear() + +此方法用于清空元素文本,可使用确保清空的方式,若元素是不可编辑的,返回 None。 + +参数: + +- insure_clear:是否确保清空。为 True 则用 input() 确保值变成 '',为 False 则用 selenium 元素 clear() 方法 + +返回:bool,是否清空成功,不能清空的元素返回 None + +```python +ele.clear() +``` + ## run_script() 此方法用于对元素执行 js 代码,代码中用 arguments[0] 表示自己。 @@ -131,20 +154,40 @@ ele.input('D:\\test1.txt\nD:\\test2.txt') ele.run_script('arguments[0].click()') ``` -## clear() +## wait_ele() -此方法用于清空元素文本,可使用确保清空的方式,若元素是不可编辑的,返回 None。 +此方法用于等待当前元素的某个下级元素到达某种状态。 +调用此方法返回一个 ElementWaiter 对象,调用该对象方法实现各种方式的等待。 参数: -- insure_clear:是否确保清空。为 True 则用 input() 确保值变成 '',为 False 则用 selenium 元素 clear() 方法 +- loc_or_ele:要等待的元素,可以是元素或定位符 +- timeout:等待超时时间,默认使用页面超时时间 -返回:bool,是否清空成功,不能清空的元素返回 None +方法: + +| 方法 | 参数说明 | 功能 | +| :-------: | :------: | :-----------------: | +| display() | 无 | 等待元素从 DOM 显示 | +| hidden() | 无 | 等待元素从 DOM 隐藏 | +| delete() | 无 | 等待元素从 DOM 删除 | + +这些方法返回布尔值,代表是否等待成功。 ```python -ele.clear() +# 等待 id 为 div1 的元素显示,超时使用页面设置 +ele.wait_ele('#div1').display() + +# 等待 id 为 div1 的元素被删除(使用 loc 元组),设置超时3秒 +ele.wait_ele((By.ID, 'div1'), 3).delete() + +# 等待已获取到的元素被隐藏 +ele2 = ele1.ele('#div1') +ele1.wait_ele(ele2).hidden() ``` + + ## screenshot() 此方法用于对元素进行截图。 @@ -163,9 +206,11 @@ ele.clear() path = ele.screenshot(r'D:\tmp', 'img_name') ``` + + ## set_prop() -此方法用于设置元素 property 属性。 +此方法用于设置元素`property`属性。 参数: @@ -211,7 +256,7 @@ ele.remove_attr('href') 此方法用于提交表单,若元素不在表单内,返回 None,否则返回 True。 -无参数。 +参数:无 返回:True 或 None @@ -259,7 +304,9 @@ ele1.drag_to(ele2) ele1.drag_to((50, 50)) ``` -## scroll_to() +## ~~scroll_to()~~ + +**注意:** 此方法将在下个版本删除,请使用 scroll 属性代替。 此方法用于按参数指示方式滚动元素中的滚动条。默认状态滚动到底端。 @@ -282,15 +329,36 @@ mode 参数可在以下选项中选择: - 'left':向左 - 'right':向右 +## scroll + +此属性用于以某种方式滚动元素中的滚动条。 +调用此属性返回一个 Scroll 对象,调用该对象方法实现各种方式的滚动。 + +| 方法 | 参数说明 | 功能 | +| :---------------: | :----------: | :------------------------------: | +| to_top() | 无 | 滚动到顶端,水平位置不变 | +| to_bottom() | 无 | 滚动到底端,水平位置不变 | +| to_half() | 无 | 滚动到垂直中间位置,水平位置不变 | +| to_rightmost() | 无 | 滚动到最右边,垂直位置不变 | +| to_leftmost() | 无 | 滚动到最左边,垂直位置不变 | +| to_location(x, y) | 滚动条坐标值 | 滚动到指定位置 | +| up(pixel) | 滚动的像素 | 向上滚动若干像素,水平位置不变 | +| down(pixel) | 滚动的像素 | 向下滚动若干像素,水平位置不变 | +| right(pixel) | 滚动的像素 | 向左滚动若干像素,垂直位置不变 | +| left(pixel) | 滚动的像素 | 向右滚动若干像素,垂直位置不变 | + ```python -# 元素滚动到底部 -ele.scroll_to() +# 滚动到底部 +ele.scroll.to_bottom() -# 元素滚动到最右边 -ele.scroll_to('rightmost') +# 滚动到最右边 +ele.scroll.to_rightmost() -# 元素向下滚动 200 像素 -ele.scroll_to('down', 200) +# 向下滚动 200 像素 +ele.scroll.down(200) + +# 滚动到指定位置 +ele.scroll.to_location(100, 300) ``` ## hover() @@ -430,7 +498,7 @@ ele.select.deselect(('index1', 'index2'), 'index') 此方法用于清空多选列表选项。 -无参数。 +参数:无 返回:None @@ -442,7 +510,7 @@ ele.select.clear() 此方法用于反选多选列表选项。 -无参数。 +参数:无 返回:None diff --git a/docs/使用方法/启动配置/Chrome启动配置.md b/docs/使用方法/启动配置/Chrome启动配置.md index c54a3a1..134fc1c 100644 --- a/docs/使用方法/启动配置/Chrome启动配置.md +++ b/docs/使用方法/启动配置/Chrome启动配置.md @@ -16,6 +16,8 @@ DriverOptions 类继承自 Options 类,保留了原来所有功能,原生功 - read_file:是否从默认 ini 文件中读取配置信息 - ini_path:ini 文件路径,为 None 则读取默认 ini 文件 + + ## driver_path 此属性返回 chromedriver 文件路径。 @@ -47,7 +49,15 @@ DriverOptions 类继承自 Options 类,保留了原来所有功能,原生功 参数: -- path:配置文件的路径,传入 None 保存到当前读取的配置文件,传入 'default' 保存到默认 ini 文件 +- path:配置文件的路径,默认保存到当前读取的配置文件,传入 'default' 保存到默认 ini 文件 + +返回:配置文件绝对路径 + +## save_to_default() + +此方法用于保存当前配置对象的信息到默认 ini 文件。 + +参数:无 返回:配置文件绝对路径 diff --git a/docs/使用方法/启动配置/Session启动配置.md b/docs/使用方法/启动配置/Session启动配置.md index b02f948..7ea3214 100644 --- a/docs/使用方法/启动配置/Session启动配置.md +++ b/docs/使用方法/启动配置/Session启动配置.md @@ -13,6 +13,8 @@ SessionOptions 对象创建时默认读取默认 ini 文件配置信息,也可 - read_file:是否从默认 ini 文件中读取配置信息 - ini_path:ini 文件路径,为 None 则读取默认 ini 文件 + + ## headers 该属性返回 headers 设置信息,可传入字典赋值。 @@ -124,7 +126,15 @@ print(so.headers) 参数: -- path:配置文件的路径,传入 None 保存到当前读取的配置文件,传入 'default' 保存到默认 ini 文件 +- path:配置文件的路径,默认保存到当前读取的配置文件,传入 'default' 保存到默认 ini 文件 + +返回:配置文件绝对路径 + +## save_to_default() + +此方法用于保存当前配置对象的信息到默认 ini 文件。 + +参数:无 返回:配置文件绝对路径 diff --git a/docs/使用方法/页面操作.md b/docs/使用方法/页面操作.md index e38d364..a96667c 100644 --- a/docs/使用方法/页面操作.md +++ b/docs/使用方法/页面操作.md @@ -6,10 +6,14 @@ 此方法用于跳转到一个 url,详细用法见“使用方法 -> 访问网页”章节。 + + ## ele()、eles()、s_ele()、s_eles() 这些方法用于在页面中查找元素,详细用法见“使用方法 -> 获取页面元素”章节。 + + ## change_mode() 此方法用于转换 MixPage 模式。 @@ -59,6 +63,8 @@ print('登录后title:', page.title) 登录后title: 个人资料 - 码云 Gitee.com ``` + + ## set_cookies() 此方法用于设置 cookies。 @@ -76,6 +82,8 @@ cookies = {'name': 'abc'} page.set_cookies(cookies) ``` + + ## cookies_to_session() 此方法用于从 WebDriver 对象复制 cookies 到 Session 对象。 @@ -86,6 +94,8 @@ page.set_cookies(cookies) 返回:None + + ## cookies_to_driver() 此方法用于从 Session 对象复制 cookies 到 WebDriver 对象。 @@ -96,10 +106,14 @@ page.set_cookies(cookies) 返回:None + + ## download() 此方法用于下载文件,详细用法见“使用方法 -> 下载文件”章节。 + + ## close_driver() 此方法用于关闭 WebDriver 对象和浏览器。 @@ -144,19 +158,34 @@ page.set_cookies(cookies) ## wait_ele() -此方法用于等待元素到达某种状态,支持显示、隐藏、删除三种。 +此方法用于等待元素到达某种状态。 +调用此方法返回一个 ElementWaiter 对象,调用该对象方法实现各种方式的等待。 参数: -- loc_or_ele:元素或定位符,支持 selenium 和本库定位符 -- mode:等待方式,可选:'del', 'display', 'hidden' -- timeout:等待超时时间 +- loc_or_ele:要等待的元素,可以是元素或定位符 +- timeout:等待超时时间,默认使用页面超时时间 -返回:是否等待成功 +方法: + +| 方法 | 参数说明 | 功能 | +| :-------: | :------: | :-----------------: | +| display() | 无 | 等待元素从 DOM 显示 | +| hidden() | 无 | 等待元素从 DOM 隐藏 | +| delete() | 无 | 等待元素从 DOM 删除 | + +这些方法返回布尔值,代表是否等待成功。 ```python -# 等待 id 为 div1 的元素被隐藏 -page.wait_ele('#div1', 'hidden', 3) +# 等待 id 为 div1 的元素显示,超时使用页面设置 +page.wait_ele('#div1').display() + +# 等待 id 为 div1 的元素被删除(使用 loc 元组),设置超时3秒 +page.wait_ele((By.ID, 'div1'), 3).delete() + +# 等待已获取到的元素被隐藏 +ele = page.ele('#div1') +paeg.wait_ele(ele).hidden() ``` ## run_script() @@ -198,43 +227,48 @@ page.run_script('alert(arguments[0]+arguments[1])', 'Hello', ' world!') 返回:None -## to_frame() +## to_frame -此方法用于将页面焦点移到某个 frame 或 iframe。 +此属性用于将页面焦点移到某个 frame 或 iframe。 +调用此属性返回一个 ToFrame 对象,调用该对象的方法实现焦点转移。 +这些方法返回值为当前页面对象,可实现下一步的链式操作。 -参数: - -- loc_or_ele:iframe的定位信息,默认跳到最顶层。 - -返回:当前页面对象,可用于链式操作 - -loc_or_ele 参数支持以下信息: - -- iframe 元素对象,DriverElement 和 WebElement 都可以 -- 本库或 selenium 定位符,如 'tag:iframe'、(By.XPATH, '//iframe') -- iframe 在页面中的序号,如 0 表示第一个 iframe -- iframe 的 id 或 name 值 -- 'main' 或 'parent' 字符串,分别代表跳转到顶层和父 iframe +| 方法 | 参数说明 | 功能 | +| :-------------: | :------------: | :--------------------------: | +| main() | 无 | 切换到顶层框架 | +| parent(level) | 第几层上级框架 | 切换到上级框架,可指定多层 | +| by_id(id) | id 属性 | 切换到`id`为该参数的框架 | +| by_name(name) | name 属性 | 切换到`name`为该参数的框架 | +| by_index(index) | 序号 | 切换到页面第几个框架,0 开始 | +| by_loc(loc) | 定位符 | 切换到定位符所指框架 | +| by_ele(ele) | 框架元素 | 传入框架元素,切换到该框架 | ```python -# 传入元素 -iframe = page.ele('tag:iframe') -page.to_frame(iframe) +# 切换到主框架 +page.to_frame.main() -# 使用定位符 +# 切换到上 2 级框架 +page.to_frame.parent(2) + +# 切换到 id 值为 'iframe_id' 的框架 +page.to_frame.by_id('iframe_id') + +# 切换到 name 值为 'iframe_name' 的框架 +page.to_frame.by_name('iframe_name') + +# 切换到页面中第一个框架 +page.to_frame.by_id(0) + +# 使用定位符查找元素,再实现切换 page.to_frame('tag:iframe') -# 使用序号,0 代表第一个 -page.to_frame(0) - -# 使用 id 或 name 值 -page.to_frame('iframe_id') - -# 使用 'main' 或 'parent' 字符串 -page.to_frame('main') -page.to_frame('parent') +# 先获取 iframe 元素,再传入实现切换 +iframe = page.ele('tag:iframe') +page.to_frame(iframe) ``` + + ## to_tab() 此方法把焦点定位到某个标签页。 @@ -311,7 +345,9 @@ reserve_list = ('aaaaa', 'bbbbb') page.close_other_tabs(reserve_list) ``` -## scroll_to() +## ~~scroll_to()~~ + +**注意:** 此方法将在下个版本删除,请使用 scroll 属性代替。 此方法用于按参数指示方式滚动页面。默认状态滚动到底端。 @@ -334,15 +370,36 @@ mode 参数可在以下选项中选择: - 'left':向左 - 'right':向右 +## scroll + +此属性用于以某种方式滚动页面。 +调用此属性返回一个 Scroll 对象,调用该对象方法实现各种方式的滚动。 + +| 方法 | 参数说明 | 功能 | +| :---------------: | :----------: | :------------------------------: | +| to_top() | 无 | 滚动到顶端,水平位置不变 | +| to_bottom() | 无 | 滚动到底端,水平位置不变 | +| to_half() | 无 | 滚动到垂直中间位置,水平位置不变 | +| to_rightmost() | 无 | 滚动到最右边,垂直位置不变 | +| to_leftmost() | 无 | 滚动到最左边,垂直位置不变 | +| to_location(x, y) | 滚动条坐标值 | 滚动到指定位置 | +| up(pixel) | 滚动的像素 | 向上滚动若干像素,水平位置不变 | +| down(pixel) | 滚动的像素 | 向下滚动若干像素,水平位置不变 | +| right(pixel) | 滚动的像素 | 向左滚动若干像素,垂直位置不变 | +| left(pixel) | 滚动的像素 | 向右滚动若干像素,垂直位置不变 | + ```python # 页面滚动到底部 -page.scroll_to() +page.scroll.to_bottom() # 页面滚动到最右边 -page.scroll_to('rightmost') +page.scroll.to_rightmost() # 页面向下滚动 200 像素 -page.scroll_to('down', 200) +page.scroll.down(200) + +# 滚动到指定位置 +page.scroll.to_location(100, 300) ``` ## scroll_to_see() @@ -362,6 +419,7 @@ page.scroll_to_see(ele) # 滚动到按定位符查找到的元素 page.scroll_to_see('tag:div') + # 也可用 selenium 定位符 page.scroll_to_see((By.XPATH, '//div')) ```