diff --git a/DrissionPage/action_chains.py b/DrissionPage/action_chains.py index 3c1d342..4f56529 100644 --- a/DrissionPage/action_chains.py +++ b/DrissionPage/action_chains.py @@ -30,7 +30,9 @@ class ActionChains: :param offset_y: 偏移量y :return: self """ + is_loc = False if isinstance(ele_or_loc, (tuple, list)): + is_loc = True lx = ele_or_loc[0] + offset_x ly = ele_or_loc[1] + offset_y elif isinstance(ele_or_loc, str) or 'ChromiumElement' in str(type(ele_or_loc)): @@ -42,9 +44,19 @@ class ActionChains: raise TypeError('ele_or_loc参数只能接受坐标(x, y)或ChromiumElement对象。') if not _location_in_viewport(self.page, lx, ly): - self.page.scroll.to_location(lx, ly) + # 把元素滚动到页面中间 + clientWidth = self.page.run_js('return document.body.clientWidth;') + clientHeight = self.page.run_js('return document.body.clientHeight;') + self.page.scroll.to_location(lx - clientWidth // 2, ly - clientHeight // 2) + + # # 这样设计为了应付那些不随滚动条滚动的元素 + if is_loc: + cx, cy = location_to_client(self.page, lx, ly) + else: + x, y = ele_or_loc.client_location if offset_x or offset_y else ele_or_loc.client_midpoint + cx = x + offset_x + cy = y + offset_y - cx, cy = location_to_client(self.page, lx, ly) self._dr.Input.dispatchMouseEvent(type='mouseMoved', x=cx, y=cy, modifiers=self.modifier) self.curr_x = cx self.curr_y = cy @@ -266,4 +278,4 @@ def location_to_client(page, lx, ly): """绝对坐标转换为视口坐标""" 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 + return lx - scroll_x, ly - scroll_y diff --git a/docs/WebPage使用方法/3.10动作链.md b/docs/WebPage使用方法/3.10动作链.md index c3576fe..89ec92c 100644 --- a/docs/WebPage使用方法/3.10动作链.md +++ b/docs/WebPage使用方法/3.10动作链.md @@ -1,17 +1,46 @@ -参考 selenium 的`ActionChains`,本库也提供了自己的`ActionChains`。语法更简洁易用,每个动作执行即生效,无须`perform()`。 +参考 selenium 的`ActionChains`,本库也提供了自己的`ActionChains`。 + +动作链可以完成一系列交互行为,如鼠标移动、鼠标点击、键盘输入等。 + +语法比 selenium 更简洁易用,每个动作执行即生效,无须`perform()`。 + +多个动作可以用链式模式操作: + +```python +ac.move_to(ele).click().type('some text') +``` + +也可以多个操作分开执行: + +```python +ac.move_to(ele) +ac.click() +ac.type('some text') +``` + +这两种方式效果是一样的,每个动作总会依次执行。 # ✔ 创建对象 +## 📍 导入 + +```python +from DrissionPage import ActionChains +``` + ## 📍 `ActionChains` 创建动作链对象非常简单,只要把`WebPage`对象或`ChromiumPage`对象传入即可。动作链只在这个页面上生效。 **参数:** -- `page`:`WebPage`对象或`ChromiumPage`对象 +| 名称 | 数据类型 | 说明 | +| ------ | ---------------------------- | ------------ | +| `page` | `WebPage`对象或`ChromiumPage`对象 | 动作链要操作的浏览器页面 | + +**示例:** ```python -# 创建前先导入 from DrissionPage import WebPage, ActionChains page = WebPage() @@ -26,13 +55,19 @@ ac = ActionChains(page) **参数:** -- `ele_or_loc`:元素对象、文本定位符或绝对坐标,坐标为`tuple`(int, int) 形式 +| 名称 | 数据类型 | 说明 | +| ------------ | ----------------------------------------- | --------------------------------------- | +| `ele_or_loc` | `ChrmoiumElement`、`str`、`Tuple[int, int]` | 元素对象、文本定位符或绝对坐标,坐标为`tuple`(int, int) 形式 | +| `offset_x` | `int` | 偏移量 x | +| `offset_y` | `int` | 偏移量 y | -- `offset_x`:偏移量 x +**返回:** -- `offset_y`:偏移量 y +| 数据类型 | 说明 | +| -------------- | ------- | +| `ActionChains` | 动作链对象本身 | -**返回:**`ActionChains`对象自己 +**示例:** ```python ele = page('tag:a') @@ -45,14 +80,23 @@ ac.move_to(ele_or_loc=ele) # 使鼠标移动过到 ele 元素上 **参数:** -- `offset_x`:偏移量 x +| 名称 | 数据类型 | 说明 | +| ---------- | ----- | ----- | +| `offset_x` | `int` | 偏移量 x | +| `offset_y` | `int` | 偏移量 y | -- `offset_y`:偏移量 y +**返回:** -**返回:**`ActionChains`对象自己 +| 数据类型 | 说明 | +| -------------- | ------- | +| `ActionChains` | 动作链对象本身 | + +**示例:** + +鼠标向右移动 300 像素 ```python -ac.move(300, 0) # 鼠标向右移动 300 像素 +ac.move(300, 0) ``` ## 📍 `up()` @@ -259,16 +303,46 @@ ac.key_down(Keys.CTRL) # 按下 ctrl 键 ac.wait(3) # 停顿 3 秒 ``` -# ✔ 链式操作 +# ✔ 示例 -以上操作皆能实现链式操作。且最后无需`perform()`。 +## 📍 模拟输入 ctrl+a ```python from DrissionPage import ChromiumPage, ActionChains +from DrissionPage.keys import Keys +# 创建页面 page = ChromiumPage() -ac = ActionCHains(page) +# 创建动作链对象 +ac = ActionChains(page) -# 链式操作 -ac.move_to('tag:h1').right(30).click().key_down('a').key_up('a') +# 鼠标移动到元素上 +ac.move_to('tag:input') +# 点击鼠标,使光标落到元素中 +ac.click() +# 按下 ctrl 键 +ac.key_down(Keys.CTRL) +# 输入 a +ac.type('a') +# 提起 ctrl 键 +ac.key_up(Keys.CTRL) +``` + +## 📍 拖拽元素 + +```python +from DrissionPage import ChromiumPage, ActionChains +from DrissionPage.keys import Keys + +# 创建页面 +page = ChromiumPage() +# 创建动作链对象 +ac = ActionChains(page) + +# 左键按住元素 +ac.hold('#div1') +# 向右移动鼠标300像素 +ac.right(300) +# 释放左键 +ac.release() ``` diff --git a/setup.py b/setup.py index 977b729..8be14a3 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ with open("README.md", "r", encoding='utf-8') as fh: setup( name="DrissionPage", - version="3.0.31", + version="3.0.32", author="g1879", author_email="g1879@qq.com", description="A module that integrates selenium and requests session, encapsulates common page operations.",