diff --git a/DrissionPage/action_chains.py b/DrissionPage/action_chains.py index 11694f0..3c1d342 100644 --- a/DrissionPage/action_chains.py +++ b/DrissionPage/action_chains.py @@ -264,6 +264,6 @@ class ActionChains: def location_to_client(page, lx, ly): """绝对坐标转换为视口坐标""" - scrool_x = page.run_script('return document.documentElement.scrollLeft;') - scrool_y = page.run_script('return document.documentElement.scrollTop;') - return lx + scrool_x, ly + scrool_y + scroll_x = page.run_js('return document.documentElement.scrollLeft;') + scroll_y = page.run_js('return document.documentElement.scrollTop;') + return lx + scroll_x, ly + scroll_y diff --git a/DrissionPage/chromium_base.py b/DrissionPage/chromium_base.py index 8241bcb..888ebd2 100644 --- a/DrissionPage/chromium_base.py +++ b/DrissionPage/chromium_base.py @@ -9,7 +9,7 @@ from time import perf_counter, sleep from requests import Session from .base import BasePage -from .chromium_element import ChromiumElementWaiter, ChromiumScroll, ChromiumElement, run_script, make_chromium_ele +from .chromium_element import ChromiumElementWaiter, ChromiumScroll, ChromiumElement, run_js, make_chromium_ele from .common import get_loc from .config import cookies_to_tuple from .session_element import make_session_ele @@ -246,14 +246,14 @@ class ChromiumBase(BasePage): @property def size(self): """返回页面总长高,格式:(长, 高)""" - w = self.run_script('document.body.scrollWidth;', as_expr=True) - h = self.run_script('document.body.scrollHeight;', as_expr=True) + w = self.run_js('document.body.scrollWidth;', as_expr=True) + h = self.run_js('document.body.scrollHeight;', as_expr=True) return w, h @property def active_ele(self): """返回当前焦点所在元素""" - return self.run_script('return document.activeElement;') + return self.run_js('return document.activeElement;') @property def page_load_strategy(self): @@ -288,16 +288,16 @@ class ChromiumBase(BasePage): if script is not None: self.timeouts.script = script - def run_script(self, script, as_expr=False, *args): + def run_js(self, script, as_expr=False, *args): """运行javascript代码 \n :param script: js文本 :param as_expr: 是否作为表达式运行,为True时args无效 :param args: 参数,按顺序在js文本中对应argument[0]、argument[1]... :return: 运行的结果 """ - return run_script(self, script, as_expr, self.timeouts.script, args) + return run_js(self, script, as_expr, self.timeouts.script, args) - def run_async_script(self, script, as_expr=False, *args): + def run_async_js(self, script, as_expr=False, *args): """以异步方式执行js代码 \n :param script: js文本 :param as_expr: 是否作为表达式运行,为True时args无效 @@ -305,7 +305,7 @@ class ChromiumBase(BasePage): :return: None """ from threading import Thread - Thread(target=run_script, args=(self, script, as_expr, self.timeouts.script, args)).start() + Thread(target=run_js, args=(self, script, as_expr, self.timeouts.script, args)).start() def get(self, url, show_errmsg=False, retry=None, interval=None, timeout=None): """访问url \n @@ -463,7 +463,7 @@ class ChromiumBase(BasePage): try: self._wait_driver.DOM.scrollIntoViewIfNeeded(nodeId=node_id) except Exception: - self.ele(loc_or_ele).run_script("this.scrollIntoView();") + self.ele(loc_or_ele).run_js("this.scrollIntoView();") def refresh(self, ignore_cache=False): """刷新当前页面 \n @@ -556,7 +556,7 @@ class ChromiumBase(BasePage): :return: sessionStorage一个或所有项内容 """ js = f'sessionStorage.getItem("{item}");' if item else 'sessionStorage;' - return self.run_script(js, as_expr=True) + return self.run_js(js, as_expr=True) def get_local_storage(self, item=None): """获取localStorage信息,不设置item则获取全部 \n @@ -564,7 +564,7 @@ class ChromiumBase(BasePage): :return: localStorage一个或所有项内容 """ js = f'localStorage.getItem("{item}");' if item else 'localStorage;' - return self.run_script(js, as_expr=True) + return self.run_js(js, as_expr=True) def set_session_storage(self, item, value): """设置或删除某项sessionStorage信息 \n @@ -573,7 +573,7 @@ class ChromiumBase(BasePage): :return: None """ js = f'sessionStorage.removeItem("{item}");' if item is False else f'sessionStorage.setItem("{item}","{value}");' - return self.run_script(js, as_expr=True) + return self.run_js(js, as_expr=True) def set_local_storage(self, item, value): """设置或删除某项localStorage信息 \n @@ -582,7 +582,7 @@ class ChromiumBase(BasePage): :return: None """ js = f'localStorage.removeItem("{item}");' if item is False else f'localStorage.setItem("{item}","{value}");' - return self.run_script(js, as_expr=True) + return self.run_js(js, as_expr=True) def clear_cache(self, session_storage=True, local_storage=True, cache=True, cookies=True): """清除缓存,可选要清除的项 \n @@ -593,9 +593,9 @@ class ChromiumBase(BasePage): :return: None """ if session_storage: - self.run_script('sessionStorage.clear();', as_expr=True) + self.run_js('sessionStorage.clear();', as_expr=True) if local_storage: - self.run_script('localStorage.clear();', as_expr=True) + self.run_js('localStorage.clear();', as_expr=True) if cache: self._wait_driver.Network.clearBrowserCache() if cookies: diff --git a/DrissionPage/chromium_base.pyi b/DrissionPage/chromium_base.pyi index 91534e6..71e814f 100644 --- a/DrissionPage/chromium_base.pyi +++ b/DrissionPage/chromium_base.pyi @@ -93,7 +93,7 @@ class ChromiumBase(BasePage): def ready_state(self) -> str: ... @property - def size(self) -> tuple: ... + def size(self) -> Tuple[int, int]: ... @property def active_ele(self) -> ChromiumElement: ... @@ -109,9 +109,9 @@ class ChromiumBase(BasePage): def set_timeouts(self, implicit: float = ..., page_load: float = ..., script: float = ...) -> None: ... - def run_script(self, script: str, as_expr: bool = ..., *args: Any) -> Any: ... + def run_js(self, script: str, as_expr: bool = ..., *args: Any) -> Any: ... - def run_async_script(self, script: str, as_expr: bool = ..., *args: Any) -> None: ... + def run_async_js(self, script: str, as_expr: bool = ..., *args: Any) -> None: ... def get(self, url: str, diff --git a/DrissionPage/chromium_element.py b/DrissionPage/chromium_element.py index 461aede..ab6db0e 100644 --- a/DrissionPage/chromium_element.py +++ b/DrissionPage/chromium_element.py @@ -46,7 +46,7 @@ class ChromiumElement(DrissionElement): else: raise RuntimeError('元素可能已失效。') - doc = self.run_script('return this.ownerDocument;') + doc = self.run_js('return this.ownerDocument;') self._doc_id = doc['objectId'] if doc else None def __repr__(self): @@ -79,7 +79,7 @@ class ChromiumElement(DrissionElement): @property def inner_html(self): """返回元素innerHTML文本""" - return self.run_script('return this.innerHTML;') + return self.run_js('return this.innerHTML;') @property def attrs(self): @@ -132,13 +132,13 @@ class ChromiumElement(DrissionElement): def client_location(self): """返回元素左上角在视口中的坐标""" m = self._get_client_rect('border') - return (m[0], m[1]) if m else (0, 0) + return (int(m[0]), int(m[1])) if m else (0, 0) @property def client_midpoint(self): """返回元素中间点在视口中的坐标""" m = self._get_client_rect('border') - return (m[0] + (m[2] - m[0]) // 2, m[3] + (m[5] - m[3]) // 2) if m else (0, 0) + return (int(m[0] + (m[2] - m[0]) // 2), int(m[3] + (m[5] - m[3]) // 2)) if m else (0, 0) @property def location(self): @@ -156,7 +156,7 @@ class ChromiumElement(DrissionElement): def _client_click_point(self): """返回元素左上角可接受点击的点视口坐标""" m = self._get_client_rect('padding') - return (self.client_midpoint[0], m[1]) if m else (0, 0) + return (int(self.client_midpoint[0]), int(m[1])) if m else (0, 0) @property def _click_point(self): @@ -284,19 +284,19 @@ class ChromiumElement(DrissionElement): @property def is_selected(self): """返回元素是否被选择""" - return self.run_script('return this.selected;') + return self.run_js('return this.selected;') @property def is_displayed(self): """返回元素是否显示""" return not (self.style('visibility') == 'hidden' - or self.run_script('return this.offsetParent === null;') + or self.run_js('return this.offsetParent === null;') or self.style('display') == 'none') @property def is_enabled(self): """返回元素是否可用""" - return not self.run_script('return this.disabled;') + return not self.run_js('return this.disabled;') @property def is_alive(self): @@ -350,14 +350,14 @@ class ChromiumElement(DrissionElement): :param value: 属性值 :return: None """ - self.run_script(f'this.setAttribute(arguments[0], arguments[1]);', False, attr, str(value)) + self.run_js(f'this.setAttribute(arguments[0], arguments[1]);', False, attr, str(value)) def remove_attr(self, attr): """删除元素attribute属性 \n :param attr: 属性名 :return: None """ - self.run_script(f'this.removeAttribute("{attr}");') + self.run_js(f'this.removeAttribute("{attr}");') def prop(self, prop): """获取property属性值 \n @@ -379,7 +379,7 @@ class ChromiumElement(DrissionElement): :return: None """ value = value.replace('"', r'\"') - self.run_script(f'this.{prop}="{value}";') + self.run_js(f'this.{prop}="{value}";') def set_innerHTML(self, html): """设置元素innerHTML \n @@ -388,16 +388,16 @@ class ChromiumElement(DrissionElement): """ self.set_prop('innerHTML', html) - def run_script(self, script, as_expr=False, *args): + def run_js(self, script, as_expr=False, *args): """运行javascript代码 \n :param script: js文本 :param as_expr: 是否作为表达式运行,为True时args无效 :param args: 参数,按顺序在js文本中对应argument[0]、argument[1]... :return: 运行的结果 """ - return run_script(self, script, as_expr, self.page.timeouts.script, args, True) + return run_js(self, script, as_expr, self.page.timeouts.script, args, True) - def run_async_script(self, script, as_expr=False, *args): + def run_async_js(self, script, as_expr=False, *args): """以异步方式执行js代码 \n :param script: js文本 :param as_expr: 是否作为表达式运行,为True时args无效 @@ -405,7 +405,7 @@ class ChromiumElement(DrissionElement): :return: None """ from threading import Thread - Thread(target=run_script, args=(self, script, as_expr, self.page.timeouts.script, args, True)).start() + Thread(target=run_js, args=(self, script, as_expr, self.page.timeouts.script, args, True)).start() def ele(self, loc_or_str, timeout=None): """返回当前元素下级符合条件的第一个元素、属性或节点文本 \n @@ -459,7 +459,7 @@ class ChromiumElement(DrissionElement): if pseudo_ele: pseudo_ele = f', "{pseudo_ele}"' if pseudo_ele.startswith(':') else f', "::{pseudo_ele}"' js = f'return window.getComputedStyle(this{pseudo_ele}).getPropertyValue("{style}");' - return self.run_script(js) + return self.run_js(js) def get_src(self): """返回元素src资源,base64的会转为bytes返回,其它返回str""" @@ -472,7 +472,7 @@ class ChromiumElement(DrissionElement): '&& this.naturalWidth > 0 && typeof this.naturalHeight != "undefined" ' '&& this.naturalHeight > 0') end_time = perf_counter() + self.page.timeout - while not self.run_script(js) and perf_counter() < end_time: + while not self.run_js(js) and perf_counter() < end_time: sleep(.1) node = self.page.run_cdp('DOM.describeNode', nodeId=self._node_id, not_change=True)['node'] @@ -519,7 +519,7 @@ class ChromiumElement(DrissionElement): '&& this.naturalWidth > 0 && typeof this.naturalHeight != "undefined" ' '&& this.naturalHeight > 0') end_time = perf_counter() + self.page.timeout - while not self.run_script(js) and perf_counter() < end_time: + while not self.run_js(js) and perf_counter() < end_time: sleep(.1) left, top = self.location @@ -577,7 +577,7 @@ class ChromiumElement(DrissionElement): :return: None """ if by_js: - self.run_script("this.value='';") + self.run_js("this.value='';") else: self.input(('\ue009', 'a', '\ue017'), clear=False) @@ -627,7 +627,7 @@ class ChromiumElement(DrissionElement): return True if by_js is not False: - self.run_script('this.click();') + self.run_js('this.click();') self.page.wait_loading(wait_loading) return True @@ -801,7 +801,7 @@ class ChromiumElement(DrissionElement): } return e(this);} ''' - t = self.run_script(js) + t = self.run_js(js) return f':root{t}' if mode == 'css' else t def _get_client_rect(self, quad): @@ -817,9 +817,9 @@ class ChromiumElement(DrissionElement): def _get_absolute_rect(self, x, y): """根据绝对坐标获取窗口坐标""" js = 'return document.documentElement.scrollLeft+" "+document.documentElement.scrollTop;' - xy = self.run_script(js) + xy = self.run_js(js) sx, sy = xy.split(' ') - return x + int(float(sx)), y + int(float(sy)) + return int(x + float(sx)), int(y + float(sy)) class ChromiumShadowRootElement(BaseElement): @@ -857,7 +857,7 @@ class ChromiumShadowRootElement(BaseElement): @property def is_enabled(self): """返回元素是否可用""" - return not self.run_script('return this.disabled;') + return not self.run_js('return this.disabled;') @property def is_alive(self): @@ -896,26 +896,26 @@ class ChromiumShadowRootElement(BaseElement): @property def inner_html(self): """返回内部的html文本""" - return self.run_script('return this.innerHTML;') + return self.run_js('return this.innerHTML;') - def run_script(self, script, as_expr=False, *args): + def run_js(self, script, as_expr=False, *args): """运行javascript代码 \n :param script: js文本 :param as_expr: 是否作为表达式运行,为True时args无效 - :param args: 参数,按顺序在js文本中对应argument[0]、argument[2]... + :param args: 参数,按顺序在js文本中对应argument[0]、argument[1]... :return: 运行的结果 """ - return run_script(self, script, as_expr, self.page.timeouts.script, args) + return run_js(self, script, as_expr, self.page.timeouts.script, args) - def run_async_script(self, script, as_expr=False, *args): + def run_async_js(self, script, as_expr=False, *args): """以异步方式执行js代码 \n :param script: js文本 :param as_expr: 是否作为表达式运行,为True时args无效 - :param args: 参数,按顺序在js文本中对应argument[0]、argument[2]... + :param args: 参数,按顺序在js文本中对应argument[0]、argument[1]... :return: None """ from threading import Thread - Thread(target=run_script, args=(self, script, as_expr, self.page.timeouts.script, args)).start() + Thread(target=run_js, args=(self, script, as_expr, self.page.timeouts.script, args)).start() def parent(self, level_or_loc=1): """返回上面某一级父元素,可指定层数或用查询语法定位 \n @@ -1248,7 +1248,7 @@ else{a.push(e.snapshotItem(i));}}""" return js -def run_script(page_or_ele, script, as_expr=False, timeout=None, args=None, not_change=False): +def run_js(page_or_ele, script, as_expr=False, timeout=None, args=None, not_change=False): """运行javascript代码 \n :param page_or_ele: 页面对象或元素对象 :param script: js文本 @@ -1416,32 +1416,32 @@ class ChromiumScroll(object): self.t1 = 'window' self.t2 = 'document.documentElement' - def _run_script(self, js): + def _run_js(self, js): js = js.format(self.t1, self.t2, self.t2) if self.t1 == 'this': # 在元素上滚动 - self.page_or_ele.run_script(js) + self.page_or_ele.run_js(js) else: - self.page_or_ele.run_script(js, as_expr=True) + self.page_or_ele.run_js(js, as_expr=True) def to_top(self): """滚动到顶端,水平位置不变""" - self._run_script('{}.scrollTo({}.scrollLeft,0);') + self._run_js('{}.scrollTo({}.scrollLeft,0);') def to_bottom(self): """滚动到底端,水平位置不变""" - self._run_script('{}.scrollTo({}.scrollLeft,{}.scrollHeight);') + self._run_js('{}.scrollTo({}.scrollLeft,{}.scrollHeight);') def to_half(self): """滚动到垂直中间位置,水平位置不变""" - self._run_script('{}.scrollTo({}.scrollLeft,{}.scrollHeight/2);') + self._run_js('{}.scrollTo({}.scrollLeft,{}.scrollHeight/2);') def to_rightmost(self): """滚动到最右边,垂直位置不变""" - self._run_script('{}.scrollTo({}.scrollWidth,{}.scrollTop);') + self._run_js('{}.scrollTo({}.scrollWidth,{}.scrollTop);') def to_leftmost(self): """滚动到最左边,垂直位置不变""" - self._run_script('{}.scrollTo(0,{}.scrollTop);') + self._run_js('{}.scrollTo(0,{}.scrollTop);') def to_location(self, x, y): """滚动到指定位置 \n @@ -1449,7 +1449,7 @@ class ChromiumScroll(object): :param y: 垂直距离 :return: None """ - self._run_script(f'{{}}.scrollTo({x},{y});') + self._run_js(f'{{}}.scrollTo({x},{y});') def up(self, pixel=300): """向上滚动若干像素,水平位置不变 \n @@ -1457,14 +1457,14 @@ class ChromiumScroll(object): :return: None """ pixel = -pixel - self._run_script(f'{{}}.scrollBy(0,{pixel});') + self._run_js(f'{{}}.scrollBy(0,{pixel});') def down(self, pixel=300): """向下滚动若干像素,水平位置不变 \n :param pixel: 滚动的像素 :return: None """ - self._run_script(f'{{}}.scrollBy(0,{pixel});') + self._run_js(f'{{}}.scrollBy(0,{pixel});') def left(self, pixel=300): """向左滚动若干像素,垂直位置不变 \n @@ -1472,14 +1472,14 @@ class ChromiumScroll(object): :return: None """ pixel = -pixel - self._run_script(f'{{}}.scrollBy({pixel},0);') + self._run_js(f'{{}}.scrollBy({pixel},0);') def right(self, pixel=300): """向右滚动若干像素,垂直位置不变 \n :param pixel: 滚动的像素 :return: None """ - self._run_script(f'{{}}.scrollBy({pixel},0);') + self._run_js(f'{{}}.scrollBy({pixel},0);') class ChromiumSelect(object): @@ -1520,7 +1520,7 @@ class ChromiumSelect(object): """返回第一个被选中的option元素 \n :return: ChromiumElement对象或None """ - ele = self._ele.run_script('return this.options[this.selectedIndex];') + ele = self._ele.run_js('return this.options[this.selectedIndex];') return ele @property @@ -1624,7 +1624,7 @@ class ChromiumSelect(object): return False js = 'false' if deselect else 'true' - ele.run_script(f'this.selected={js};') + ele.run_js(f'this.selected={js};') return True diff --git a/DrissionPage/chromium_element.pyi b/DrissionPage/chromium_element.pyi index 565de68..4bab636 100644 --- a/DrissionPage/chromium_element.pyi +++ b/DrissionPage/chromium_element.pyi @@ -66,25 +66,25 @@ class ChromiumElement(DrissionElement): def doc_id(self) -> str: ... @property - def size(self) -> tuple: ... + def size(self) -> Tuple[int, int]: ... @property - def client_location(self) -> tuple: ... + def client_location(self) -> Tuple[int, int]: ... @property - def client_midpoint(self) -> tuple: ... + def client_midpoint(self) -> Tuple[int, int]: ... @property - def location(self) -> tuple: ... + def location(self) -> Tuple[int, int]: ... @property - def midpoint(self) -> tuple: ... + def midpoint(self) -> Tuple[int, int]: ... @property - def _client_click_point(self) -> tuple: ... + def _client_click_point(self) -> Tuple[int, int]: ... @property - def _click_point(self) -> tuple: ... + def _click_point(self) -> Tuple[int, int]: ... @property def shadow_root(self) -> Union[None, ChromiumShadowRootElement]: ... @@ -169,9 +169,9 @@ class ChromiumElement(DrissionElement): def set_innerHTML(self, html: str) -> None: ... - def run_script(self, script: str, as_expr: bool = ..., *args: Any) -> Any: ... + def run_js(self, script: str, as_expr: bool = ..., *args: Any) -> Any: ... - def run_async_script(self, script: str, as_expr: bool = ..., *args: Any) -> None: ... + def run_async_js(self, script: str, as_expr: bool = ..., *args: Any) -> None: ... def ele(self, loc_or_str: Union[Tuple[str, str], str], @@ -236,7 +236,7 @@ class ChromiumElement(DrissionElement): def _get_client_rect(self, quad: str) -> Union[list, None]: ... - def _get_absolute_rect(self, x: int, y: int) -> tuple: ... + def _get_absolute_rect(self, x: int, y: int) -> Tuple[int, int]: ... class ChromiumShadowRootElement(BaseElement): @@ -281,9 +281,9 @@ class ChromiumShadowRootElement(BaseElement): @property def inner_html(self) -> str: ... - def run_script(self, script: str, as_expr: bool = ..., *args: Any) -> Any: ... + def run_js(self, script: str, as_expr: bool = ..., *args: Any) -> Any: ... - def run_async_script(self, script: str, as_expr: bool = ..., *args: Any) -> None: ... + def run_async_js(self, script: str, as_expr: bool = ..., *args: Any) -> None: ... def parent(self, level_or_loc: Union[str, int] = ...) -> ChromiumElement: ... @@ -358,8 +358,8 @@ def make_chromium_ele(page: ChromiumBase, node_id: str = ..., obj_id: str = ...) def _make_js_for_find_ele_by_xpath(xpath: str, type_txt: str, node_txt: str) -> str: ... -def run_script(page_or_ele: Union[ChromiumBase, ChromiumElement, ChromiumShadowRootElement], script: str, - as_expr: bool = ..., timeout: float = ..., args: tuple = ..., not_change: bool = ...) -> Any: ... +def run_js(page_or_ele: Union[ChromiumBase, ChromiumElement, ChromiumShadowRootElement], script: str, + as_expr: bool = ..., timeout: float = ..., args: tuple = ..., not_change: bool = ...) -> Any: ... def _parse_js_result(page: ChromiumBase, ele: ChromiumElement, result: dict): ... @@ -384,7 +384,7 @@ class ChromiumScroll(object): self.t2: str = ... self.page_or_ele: Union[ChromiumPage, ChromiumElement] = ... - def _run_script(self, js: str): ... + def _run_js(self, js: str): ... def to_top(self) -> None: ... diff --git a/DrissionPage/chromium_frame.py b/DrissionPage/chromium_frame.py index 430f281..8c05c49 100644 --- a/DrissionPage/chromium_frame.py +++ b/DrissionPage/chromium_frame.py @@ -26,7 +26,7 @@ class ChromiumFrame(ChromiumBase): else: self._is_diff_domain = True super().__init__(page.address, self.frame_id, page.timeout) - obj_id = super().run_script('document;', as_expr=True)['objectId'] + obj_id = super().run_js('document;', as_expr=True)['objectId'] self.doc_ele = ChromiumElement(self, obj_id=obj_id) def __call__(self, loc_or_str, timeout=None): @@ -55,7 +55,7 @@ class ChromiumFrame(ChromiumBase): self._is_diff_domain = True self._tab_obj.stop() super().__init__(self.address, self.frame_id, self.page.timeout) - obj_id = super().run_script('document;', as_expr=True)['objectId'] + obj_id = super().run_js('document;', as_expr=True)['objectId'] self.doc_ele = ChromiumElement(self, obj_id=obj_id) def _check_ok(self): @@ -148,7 +148,7 @@ class ChromiumFrame(ChromiumBase): def url(self): """返回frame当前访问的url""" self._check_ok() - return self.doc_ele.run_script('return this.location.href;') + return self.doc_ele.run_js('return this.location.href;') @property def html(self): @@ -164,7 +164,7 @@ class ChromiumFrame(ChromiumBase): def inner_html(self): """返回元素innerHTML文本""" self._check_ok() - return self.doc_ele.run_script('return this.documentElement.outerHTML;') + return self.doc_ele.run_js('return this.documentElement.outerHTML;') @property def title(self): @@ -176,7 +176,7 @@ class ChromiumFrame(ChromiumBase): def cookies(self): """以dict格式返回cookies""" self._check_ok() - return super().cookies if self._is_diff_domain else self.doc_ele.run_script('return this.cookie;') + return super().cookies if self._is_diff_domain else self.doc_ele.run_js('return this.cookie;') @property def attrs(self): @@ -188,8 +188,8 @@ class ChromiumFrame(ChromiumBase): def frame_size(self): """返回frame内页面尺寸,格式:(长, 高)""" self._check_ok() - w = self.doc_ele.run_script('return this.body.scrollWidth') - h = self.doc_ele.run_script('return this.body.scrollHeight') + w = self.doc_ele.run_js('return this.body.scrollWidth') + h = self.doc_ele.run_js('return this.body.scrollHeight') return w, h @property @@ -202,7 +202,7 @@ class ChromiumFrame(ChromiumBase): def active_ele(self): """返回当前焦点所在元素""" self._check_ok() - return self.doc_ele.run_script('return this.activeElement;') + return self.doc_ele.run_js('return this.activeElement;') @property def location(self): @@ -240,14 +240,14 @@ class ChromiumFrame(ChromiumBase): else: while True: try: - return self.doc_ele.run_script('return this.readyState;') + return self.doc_ele.run_js('return this.readyState;') except: pass def refresh(self): """刷新frame页面""" self._check_ok() - self.doc_ele.run_script('this.location.reload();') + self.doc_ele.run_js('this.location.reload();') def attr(self, attr): """返回frame元素attribute属性值 \n @@ -274,7 +274,7 @@ class ChromiumFrame(ChromiumBase): self._check_ok() self.frame_ele.remove_attr(attr) - def run_script(self, script, as_expr=False, *args): + def run_js(self, script, as_expr=False, *args): """运行javascript代码 \n :param script: js文本 :param as_expr: 是否作为表达式运行,为True时args无效 @@ -282,7 +282,7 @@ class ChromiumFrame(ChromiumBase): :return: 运行的结果 """ self._check_ok() - return self.doc_ele.run_script(script, as_expr=as_expr, *args) + return self.doc_ele.run_js(script, as_expr=as_expr, *args) def parent(self, level_or_loc=1): """返回上面某一级父元素,可指定层数或用查询语法定位 \n diff --git a/DrissionPage/chromium_frame.pyi b/DrissionPage/chromium_frame.pyi index 12a8cdc..3871b58 100644 --- a/DrissionPage/chromium_frame.pyi +++ b/DrissionPage/chromium_frame.pyi @@ -75,16 +75,16 @@ class ChromiumFrame(ChromiumBase): def attrs(self) -> dict: ... @property - def frame_size(self) -> tuple: ... + def frame_size(self) -> Tuple[int, int]: ... @property - def size(self) -> tuple: ... + def size(self) -> Tuple[int, int]: ... @property def active_ele(self) -> ChromiumElement: ... @property - def location(self) -> dict: ... + def location(self) -> Tuple[int, int]: ... @property def is_displayed(self) -> bool: ... @@ -103,7 +103,7 @@ class ChromiumFrame(ChromiumBase): def remove_attr(self, attr: str) -> None: ... - def run_script(self, script: str, as_expr: bool = ..., *args: Any) -> Any: ... + def run_js(self, script: str, as_expr: bool = ..., *args: Any) -> Any: ... def parent(self, level_or_loc: Union[tuple, str, int] = ...) -> Union[ChromiumElement, None]: ... diff --git a/DrissionPage/common.py b/DrissionPage/common.py index b4d29eb..a465896 100644 --- a/DrissionPage/common.py +++ b/DrissionPage/common.py @@ -672,4 +672,4 @@ def _location_in_viewport(page, loc_x: int, loc_y: int) -> bool: if (x< document.documentElement.scrollLeft || y < document.documentElement.scrollTop || x > vWidth || y > vHeight){{return false;}} return true;}}''' - return page.run_script(js) + return page.run_js(js) diff --git a/docs/README.md b/docs/README.md index a2a2108..d9b6181 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,28 +1,37 @@ -# ✨️简洁!易用 !方便!✨️ +DrissionPage 是一个基于 python 的网页自动化工具。 -DrissionPage,即 driver 和 session 组合而成的 page。 -是个基于 python 的 Web 自动化操作集成工具。 -它用 POM 模式封装了页面和元素常用的方法, -自带一套简洁直观优雅的元素定位语法, -实现了浏览器和 requests 之间的无缝切换, -可兼顾浏览器自动化的便利性和 requests 的高效率, -更棒的是,它的使用方式非常简洁和人性化,代码量少,对新手友好。 +它既能控制浏览器,也能收发数据包,甚至能把两者合而为一, + +可兼顾浏览器自动化的便利性和 requests 的高效率。 + +它功能强大,内置无数人性化设计和便捷功能。 + +它的语法简洁而优雅,代码量少,对新手友好。 **交流QQ群:** 897838127 **联系邮箱:** g1879@qq.com -## 📕 背景 +# 📕 背景 -用 requests 做数据采集面对要登录的网站时,要分析数据包、JS 源码,构造复杂的请求,往往还要应付验证码、JS 混淆、签名参数等反爬手段,门槛较高。若数据是由 JS 计算生成的,还须重现计算过程,体验不好,开发效率不高。 -使用浏览器,可以很大程度上绕过这些坑,但浏览器运行效率不高。因此,这个库将它们合而为一,不同须要时切换相应模式,并提供一种人性化的使用方法,提高开发和运行效率。 +用 requests 做数据采集面对要登录的网站时,要分析数据包、JS 源码,构造复杂的请求,往往还要应付验证码、JS 混淆、签名参数等反爬手段,门槛较高。若数据是由 JS 计算生成的,还须重现计算过程,体验不好,开发效率不高。 +使用浏览器,可以很大程度上绕过这些坑,但浏览器运行效率不高。 + +因此,这个库设计初衷,是将它们合而为一,能够在不同须要时切换相应模式,并提供一种人性化的使用方法,提高开发和运行效率。 除了合并两者,本库还以网页为单位封装了常用功能,提供非常简便的操作和语句,在用于网页自动化操作时,减少考虑细节,专注功能实现,使用更方便。 一切从简,尽量提供简单直接的使用方法,对新手更友好。 -# 🔆 3.0 版隆重推出 +# ✨️ 理念 -以前的版本是对 selenium 进行重新封装实现的。从 3.0 开始,作者另起炉灶,对底层进行了重新开发,摆脱对 selenium 的依赖,增强了功能,提升了运行效率。 -3.0 全新开发的页面对象是`WebPage`,支持 chromium 内核的浏览器(如 chrome 和 edge)。除了保持之前的功能,比依赖 selenium 的`MixPage`有以下优点: +简洁!易用 !方便! + +# 💡 特性和亮点 + +作者经过长期实践,踩过无数坑,总结出的经验全写到这个库里了。 + +## 🎇 强大的自研内核 + +本库采用全自研的内核,内置了 N 多实用功能,对常用功能作了整合和优化,对比 selenium,有以下优点: - 无 webdriver 特征,不会被网站识别 @@ -40,52 +49,20 @@ DrissionPage,即 driver 和 session 组合而成的 page。 - 可以对整个网页截图,包括视口外的部分(90以上版本浏览器支持) -- 对 Linux 提供良好支持 - -新版是自己实现的功能,开发不会受太多限制,以后将主要对`WebPage`进行更新。 - -3.0 版已经发布,目前正在测试,欢迎试用并提出意见,让我做得更好。 - - - -# 💡 特性和亮点 - -作者踩过无数坑,总结出的经验全写到这个库里了。内置了 N 多实用功能,对常用功能作了整合和优化。 - -## 🎉 特性 - -- 代码高度集成,以简洁的代码为第一追求。 -- 页面对象可在浏览器和 requests 模式间任意切换,保留登录状态。 -- 极简单但强大的元素定位语法,支持链式操作,代码极其简洁。 -- 两种模式提供一致的 API,使用体验一致。 -- 人性化设计,集成众多实用功能,大大降低开发工作量。 - ## 🎇 亮点功能 -- 每次运行程序可以反复使用已经打开的浏览器。如手动设置网页到某个状态,再用程序接管,或手动处理登录,再用程序爬内容。无须每次运行从头启动浏览器,超级方便。 -- 使用 ini 文件保存常用配置,自动调用,也提供便捷的设置 API,远离繁杂的配置项。 -- 极致简明的定位语法,支持直接按文本定位元素,支持直接获取前后兄弟元素和父元素等。 -- 强大的下载工具,操作浏览器时也能享受快捷可靠的下载功能。 -- 下载工具支持多种方式处理文件名冲突、自动创建目标路径、断链重试等。 -- 访问网址带自动重试功能,可设置间隔和超时时间。 -- 访问网页能自动识别编码,无须手动设置。 -- 链接参数默认自动生成`Host`和`Referer`属性。 -- 可随时直接隐藏或显示浏览器进程窗口,非 headless 或最小化。 -- 可自动下载合适版本的 chromedriver,免去麻烦的配置。 -- d 模式查找元素内置等待,可任意设置全局等待时间或单次查找等待时间。 -- 点击元素集成 js 点击方式,一个参数即可切换点击方式。 -- 点击支持失败重试,可用于保证点击成功、判读网页遮罩层是否消失等。 -- 输入文本能自动判断是否成功并重试,避免某些情况下输入或清空失效的情况。 -- d 模式下支持全功能的 xpath,可直接获取元素的某个属性,selenium 原生无此功能。 -- 支持直接获取`shadow-root`,和普通元素一样操作其下的元素。 -- 支持直接获取`after`和`before`伪元素的内容。 -- 可以在元素下直接使用 > 以 css selector 方式获取当前元素直接子元素。原生不支持这种写法。 -- 可简单地使用 lxml 来解析 d 模式的页面或元素,爬取复杂页面数据时速度大幅提高。 -- 输出的数据均已转码及处理基本排版,减少重复劳动。 -- 可方便地与 selenium 或 requests 原生代码对接,便于项目迁移。 -- 使用 POM 模式封装,可直接用于测试,便于扩展。 -- d 模式配置可同时兼容`debugger_address`和其它参数,原生不能兼容。 -- 还有很多这里不一一列举………… +除了以上优点,本库还内置了无数人性化设计。 + +- 极简的语法规则。集成大量常用功能,代码更优雅 +- 定位元素更加容易,功能更强大稳定 +- 无处不在的等待和自动重试功能。使不稳定的网络变得易于控制,程序更稳定,编写更省心 +- 提供强大的下载工具。操作浏览器时也能享受快捷可靠的下载功能 +- 允许反复使用已经打开的浏览器。无须每次运行从头启动浏览器,调试超方便 +- 使用 ini 文件保存常用配置,自动调用,提供便捷的设置,远离繁杂的配置项 +- 内置 lxml 作为解析引擎,解析速度成几个数量级提升 +- 使用 POM 模式封装,可直接用于测试,便于扩展 +- 高度集成的便利功能,从每个细节中体现 +- 还有很多细节,这里不一一列举,欢迎实际使用中体验:) # 🖐🏻 免责声明 diff --git a/docs/WebPage使用方法/3.5元素操作.md b/docs/WebPage使用方法/3.5元素操作.md index 2bb1ea3..d7a4315 100644 --- a/docs/WebPage使用方法/3.5元素操作.md +++ b/docs/WebPage使用方法/3.5元素操作.md @@ -40,7 +40,7 @@ ele.click(by_js=True) # 无视遮罩层,直接用 js 点击下方元素 ## 📍 `click_at()` -此方法用于带偏移量点击元素,偏移量相对于元素左上角坐标。不传入`offset_x`或`offset_y`值时点击元素左上角可接受点击的点。 +此方法用于带偏移量点击元素,偏移量相对于元素左上角坐标。不传入`offset_x`或`offset_y`值时点击元素中上部可接受点击的点。 可用于点击一些奇怪的东西,比如用伪元素表示的控件。 点击的目标不一定在元素上,可以传入负值,或大于元素大小的值,点击元素附近的区域。向右和向下为正值,向左和向上为负值。 @@ -48,7 +48,7 @@ ele.click(by_js=True) # 无视遮罩层,直接用 js 点击下方元素 - `offset_x`:相对元素左上角坐标的 x 轴偏移量 - `offset_y`:相对元素左上角坐标的 y 轴偏移量 -- `button`:点击哪个键,传入`'left'`或`right` +- `button`:点击哪个键,传入`'left'`、`'right'`或`'middle'` **返回:**`None` @@ -161,9 +161,11 @@ from DrissionPage.keys import Keys ele.input((Keys.CTRL, 'a', Keys.DEL)) # ctrl+a+del ``` -## 📍 上传文件控件 +## 📍 上传文件 -上传文件也是用`input()`输入,用法与输入文本一致,稍有不同的是无论`clear`是什么,都会清空原控件内容。 +上传文件是用`input()`对`type`属性为`'file'`的``元素进行输入,把文件路径输入到元素即可,用法与输入文本一致。 + +稍有不同的是,无论`clear`参数是什么,都会清空原控件内容。 多文件上传控件,多个路径以`list`、`tuple`或以`\n`分隔的字符串传入。 @@ -304,7 +306,7 @@ ele.remove_attr('href') # ✔️ 执行 js 脚本 -## 📍 `run_script()` +## 📍 `run_js()` 此方法用于对元素执行 js 代码,代码中用`this`表示元素自己。 @@ -320,10 +322,10 @@ ele.remove_attr('href') ```python # 用执行 js 的方式点击元素 -ele.run_script('this.click();') +ele.run_js('this.click();') # 用 js 获取元素高度 -height = ele.run_script('return this.offsetHeight;') +height = ele.run_js('return this.offsetHeight;') ``` ## 📍 `run_async_script()` diff --git a/docs/WebPage使用方法/3.7页面操作.md b/docs/WebPage使用方法/3.7页面操作.md index c637c17..1036f59 100644 --- a/docs/WebPage使用方法/3.7页面操作.md +++ b/docs/WebPage使用方法/3.7页面操作.md @@ -164,7 +164,7 @@ print('登录后title:', page.title) # ✔️ 执行脚本或命令 -## 📍 `run_script()` +## 📍 `run_js()` 此方法用于执行 js 脚本,d 模式独有。 @@ -178,7 +178,7 @@ print('登录后title:', page.title) ```python # 用传入参数的方式执行 js 脚本显示弹出框显示 Hello world! -page.run_script('alert(arguments[0]+arguments[1]);', 'Hello', ' world!') +page.run_js('alert(arguments[0]+arguments[1]);', 'Hello', ' world!') ``` ## 📍 `run_async_script()` diff --git a/docs/WebPage使用方法/3.9iframe操作.md b/docs/WebPage使用方法/3.9iframe操作.md index df9341d..f5fbb2a 100644 --- a/docs/WebPage使用方法/3.9iframe操作.md +++ b/docs/WebPage使用方法/3.9iframe操作.md @@ -243,7 +243,7 @@ iframe.refresh() 此属性以`tuple`形式返回页面大小。 -## 📍 `run_script()` +## 📍 `run_js()` 此方法用于在`